Search in sources :

Example 16 with UnboundExpression

use of org.datanucleus.store.rdbms.sql.expression.UnboundExpression in project datanucleus-rdbms by datanucleus.

the class QueryToSQLMapper method processEqExpression.

/* (non-Javadoc)
     * @see org.datanucleus.query.evaluator.AbstractExpressionEvaluator#processEqExpression(org.datanucleus.query.expression.Expression)
     */
protected Object processEqExpression(Expression expr) {
    SQLExpression right = stack.pop();
    SQLExpression left = stack.pop();
    if (left instanceof ParameterLiteral && !(right instanceof ParameterLiteral)) {
        left = replaceParameterLiteral((ParameterLiteral) left, right.getJavaTypeMapping());
    } else if (right instanceof ParameterLiteral && !(left instanceof ParameterLiteral)) {
        right = replaceParameterLiteral((ParameterLiteral) right, left.getJavaTypeMapping());
    }
    if (left.isParameter() && right.isParameter()) {
        if (left.isParameter() && left instanceof SQLLiteral && ((SQLLiteral) left).getValue() != null) {
            // Change this parameter to a plain literal
            useParameterExpressionAsLiteral((SQLLiteral) left);
        }
        if (right.isParameter() && right instanceof SQLLiteral && ((SQLLiteral) right).getValue() != null) {
            // Change this parameter to a plain literal
            useParameterExpressionAsLiteral((SQLLiteral) right);
        }
    }
    ExpressionUtils.checkAndCorrectExpressionMappingsForBooleanComparison(left, right);
    if (left instanceof UnboundExpression) {
        processUnboundExpression((UnboundExpression) left);
        left = stack.pop();
    }
    if (right instanceof UnboundExpression) {
        processUnboundExpression((UnboundExpression) right);
        right = stack.pop();
    }
    // Logic for when one side is cross-joined (variable) and other side not, so transfer to a left outer join
    if (!options.contains(OPTION_EXPLICIT_JOINS)) {
        boolean leftIsCrossJoin = (stmt.getJoinTypeForTable(left.getSQLTable()) == JoinType.CROSS_JOIN);
        boolean rightIsCrossJoin = (stmt.getJoinTypeForTable(right.getSQLTable()) == JoinType.CROSS_JOIN);
        if (leftIsCrossJoin && !rightIsCrossJoin && !(right instanceof SQLLiteral)) {
            // "a == b" and a is cross-joined currently (includes variable) so change to left outer join
            String varName = getAliasForSQLTable(left.getSQLTable());
            JoinType joinType = getRequiredJoinTypeForAlias(varName);
            if (joinType != null) {
                NucleusLogger.QUERY.debug("QueryToSQL.eq variable " + varName + " is mapped to table " + left.getSQLTable() + " was previously bound as CROSS JOIN but changing to " + joinType);
                String leftTblAlias = stmt.removeCrossJoin(left.getSQLTable());
                if (joinType == JoinType.LEFT_OUTER_JOIN) {
                    stmt.join(JoinType.LEFT_OUTER_JOIN, right.getSQLTable(), right.getJavaTypeMapping(), left.getSQLTable().getTable(), leftTblAlias, left.getJavaTypeMapping(), null, left.getSQLTable().getGroupName(), true);
                } else {
                    stmt.join(JoinType.INNER_JOIN, right.getSQLTable(), right.getJavaTypeMapping(), left.getSQLTable().getTable(), leftTblAlias, left.getJavaTypeMapping(), null, left.getSQLTable().getGroupName(), true);
                }
                JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
                SQLExpression opExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
                stack.push(opExpr);
                return opExpr;
            }
        } else if (!leftIsCrossJoin && rightIsCrossJoin && !(left instanceof SQLLiteral)) {
            // "a == b" and b is cross-joined currently (includes variable) so change to left outer join
            String varName = getAliasForSQLTable(right.getSQLTable());
            JoinType joinType = getRequiredJoinTypeForAlias(varName);
            if (joinType != null) {
                NucleusLogger.QUERY.debug("QueryToSQL.eq variable " + varName + " is mapped to table " + right.getSQLTable() + " was previously bound as CROSS JOIN but changing to " + joinType);
                String rightTblAlias = stmt.removeCrossJoin(right.getSQLTable());
                if (joinType == JoinType.LEFT_OUTER_JOIN) {
                    stmt.join(JoinType.LEFT_OUTER_JOIN, left.getSQLTable(), left.getJavaTypeMapping(), right.getSQLTable().getTable(), rightTblAlias, right.getJavaTypeMapping(), null, right.getSQLTable().getGroupName(), true);
                } else {
                    stmt.join(JoinType.INNER_JOIN, left.getSQLTable(), left.getJavaTypeMapping(), right.getSQLTable().getTable(), rightTblAlias, right.getJavaTypeMapping(), null, right.getSQLTable().getGroupName(), true);
                }
                JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
                SQLExpression opExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
                stack.push(opExpr);
                return opExpr;
            }
        }
    }
    BooleanExpression opExpr = left.eq(right);
    stack.push(opExpr);
    return opExpr;
}
Also used : BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) ParameterLiteral(org.datanucleus.store.rdbms.sql.expression.ParameterLiteral) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) JoinType(org.datanucleus.store.rdbms.sql.SQLJoin.JoinType) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression)

Example 17 with UnboundExpression

use of org.datanucleus.store.rdbms.sql.expression.UnboundExpression in project datanucleus-rdbms by datanucleus.

the class QueryToSQLMapper method compileResult.

/**
 * Method to compile the result clause of the query into the SQLStatement.
 * Note that this also compiles queries of the candidate (no specified result), selecting the candidate field(s).
 * @param stmt SELECT statement
 */
protected void compileResult(SelectStatement stmt) {
    compileComponent = CompilationComponent.RESULT;
    boolean unionsPresent = stmt.getNumberOfUnions() > 0;
    // TODO Cater for more expression types where we have UNIONs and select each UNION separately
    if (compilation.getExprResult() != null) {
        // Select any result expressions
        Expression[] resultExprs = compilation.getExprResult();
        for (int i = 0; i < resultExprs.length; i++) {
            String alias = resultExprs[i].getAlias();
            if (alias != null && resultAliases == null) {
                resultAliases = new HashSet<>();
            }
            if (resultExprs[i] instanceof InvokeExpression || resultExprs[i] instanceof ParameterExpression || resultExprs[i] instanceof Literal) {
                // Process expressions that need no special treatment
                if (resultExprs[i] instanceof InvokeExpression) {
                    processInvokeExpression((InvokeExpression) resultExprs[i]);
                } else if (resultExprs[i] instanceof ParameterExpression) {
                    // Second argument : parameters are literals in result
                    processParameterExpression((ParameterExpression) resultExprs[i], true);
                } else {
                    processLiteral((Literal) resultExprs[i]);
                }
                SQLExpression sqlExpr = stack.pop();
                validateExpressionForResult(sqlExpr);
                int[] cols = stmt.select(sqlExpr, alias);
                StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
                idx.setColumnPositions(cols);
                if (alias != null) {
                    resultAliases.add(alias);
                    idx.setColumnAlias(alias);
                }
                resultDefinition.addMappingForResultExpression(i, idx);
            } else if (resultExprs[i] instanceof PrimaryExpression) {
                PrimaryExpression primExpr = (PrimaryExpression) resultExprs[i];
                if (primExpr.getId().equals(candidateAlias)) {
                    // "this", so select fetch plan fields
                    if (unionsPresent) {
                        // Process the first union separately (in case they have TYPE/instanceof) and then handle remaining UNIONs below
                        stmt.setAllowUnions(false);
                    }
                    StatementClassMapping map = new StatementClassMapping(candidateCmd.getFullClassName(), null);
                    SQLStatementHelper.selectFetchPlanOfCandidateInStatement(stmt, map, candidateCmd, fetchPlan, 1);
                    resultDefinition.addMappingForResultExpression(i, map);
                    if (unionsPresent) {
                        // Process remaining UNIONs. Assumed that we have the same result mapping as the first UNION otherwise SQL wouldn't work anyway
                        stmt.setAllowUnions(true);
                        List<SelectStatement> unionStmts = stmt.getUnions();
                        SelectStatement originalStmt = stmt;
                        for (SelectStatement unionStmt : unionStmts) {
                            this.stmt = unionStmt;
                            unionStmt.setQueryGenerator(this);
                            unionStmt.setAllowUnions(false);
                            StatementClassMapping dummyClsMapping = new StatementClassMapping(candidateCmd.getFullClassName(), null);
                            SQLStatementHelper.selectFetchPlanOfCandidateInStatement(unionStmt, dummyClsMapping, candidateCmd, fetchPlan, 1);
                            unionStmt.setQueryGenerator(null);
                            unionStmt.setAllowUnions(true);
                        }
                        this.stmt = originalStmt;
                    }
                } else {
                    processPrimaryExpression(primExpr);
                    SQLExpression sqlExpr = stack.pop();
                    validateExpressionForResult(sqlExpr);
                    if (primExpr.getId().endsWith("#KEY") || primExpr.getId().endsWith("#VALUE")) {
                        // JPQL KEY(map) or VALUE(map), so select FetchPlan fields where persistable
                        if (sqlExpr.getJavaTypeMapping() instanceof PersistableMapping) {
                            // Method returns persistable object, so select the FetchPlan
                            String selectedType = ((PersistableMapping) sqlExpr.getJavaTypeMapping()).getType();
                            AbstractClassMetaData selectedCmd = ec.getMetaDataManager().getMetaDataForClass(selectedType, clr);
                            FetchPlanForClass fpForCmd = fetchPlan.getFetchPlanForClass(selectedCmd);
                            int[] membersToSelect = fpForCmd.getMemberNumbers();
                            ClassTable selectedTable = (ClassTable) sqlExpr.getSQLTable().getTable();
                            StatementClassMapping map = new StatementClassMapping(selectedCmd.getFullClassName(), null);
                            if (selectedCmd.getIdentityType() == IdentityType.DATASTORE) {
                                int[] cols = stmt.select(sqlExpr.getSQLTable(), selectedTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false), alias);
                                StatementMappingIndex idx = new StatementMappingIndex(selectedTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false));
                                idx.setColumnPositions(cols);
                                map.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), idx);
                            }
                            // Select the FetchPlan members
                            for (int memberToSelect : membersToSelect) {
                                AbstractMemberMetaData selMmd = selectedCmd.getMetaDataForManagedMemberAtAbsolutePosition(memberToSelect);
                                // TODO Arbitrary penultimate argument
                                SQLStatementHelper.selectMemberOfSourceInStatement(stmt, map, fetchPlan, sqlExpr.getSQLTable(), selMmd, clr, 1, null);
                            }
                            resultDefinition.addMappingForResultExpression(i, map);
                            continue;
                        } else if (sqlExpr.getJavaTypeMapping() instanceof EmbeddedMapping) {
                            // Method returns embedded object, so select the FetchPlan
                            EmbeddedMapping embMapping = (EmbeddedMapping) sqlExpr.getJavaTypeMapping();
                            AbstractClassMetaData selectedCmd = ec.getMetaDataManager().getMetaDataForClass(embMapping.getType(), clr);
                            // Select the FetchPlan members
                            StatementClassMapping map = new StatementClassMapping(selectedCmd.getFullClassName(), null);
                            int[] membersToSelect = fetchPlan.getFetchPlanForClass(selectedCmd).getMemberNumbers();
                            for (int memberToSelect : membersToSelect) {
                                AbstractMemberMetaData selMmd = selectedCmd.getMetaDataForManagedMemberAtAbsolutePosition(memberToSelect);
                                JavaTypeMapping selMapping = embMapping.getJavaTypeMapping(selMmd.getName());
                                if (selMapping.includeInFetchStatement()) {
                                    int[] cols = stmt.select(sqlExpr.getSQLTable(), selMapping, alias);
                                    StatementMappingIndex idx = new StatementMappingIndex(selMapping);
                                    idx.setColumnPositions(cols);
                                    map.addMappingForMember(memberToSelect, idx);
                                }
                            }
                            resultDefinition.addMappingForResultExpression(i, map);
                            continue;
                        }
                    }
                    // TODO If the user selects an alias here that is joined, should maybe respect FetchPlan for that (like above for candidate)
                    // TODO Cater for use of UNIONs (e.g "complete-table" inheritance) where mapping is different in other UNION
                    // The difficulty here is that processPrimaryExpression makes use of the sqlTableByPrimary lookup, which is based on the primary statement, so
                    // it still doesn't find the right table/mapping for the UNIONed statements.
                    int[] cols = null;
                    if (sqlExpr instanceof SQLLiteral) {
                        cols = stmt.select(sqlExpr, alias);
                    } else {
                        cols = stmt.select(sqlExpr.getSQLTable(), sqlExpr.getJavaTypeMapping(), alias);
                    }
                    StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
                    idx.setColumnPositions(cols);
                    if (alias != null) {
                        resultAliases.add(alias);
                        idx.setColumnAlias(alias);
                    }
                    resultDefinition.addMappingForResultExpression(i, idx);
                }
            } else if (resultExprs[i] instanceof VariableExpression) {
                // Subquery?
                processVariableExpression((VariableExpression) resultExprs[i]);
                SQLExpression sqlExpr = stack.pop();
                validateExpressionForResult(sqlExpr);
                if (sqlExpr instanceof UnboundExpression) {
                    // Variable wasn't bound in the compilation so far, so handle as cross-join
                    processUnboundExpression((UnboundExpression) sqlExpr);
                    sqlExpr = stack.pop();
                    NucleusLogger.QUERY.debug("QueryToSQL.exprResult variable was still unbound, so binding via cross-join");
                }
                int[] cols = stmt.select(sqlExpr, alias);
                StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
                idx.setColumnPositions(cols);
                if (alias != null) {
                    resultAliases.add(alias);
                    idx.setColumnAlias(alias);
                }
                resultDefinition.addMappingForResultExpression(i, idx);
            } else if (resultExprs[i] instanceof TypeExpression) {
                // TYPE(identification_variable | single_valued_path_expr | input_parameter)
                TypeExpression typeExpr = (TypeExpression) resultExprs[i];
                Expression containedExpr = typeExpr.getContainedExpression();
                if (containedExpr instanceof PrimaryExpression) {
                    processPrimaryExpression((PrimaryExpression) containedExpr);
                    SQLExpression sqlExpr = stack.pop();
                    JavaTypeMapping discrimMapping = sqlExpr.getSQLTable().getTable().getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
                    if (discrimMapping == null) {
                        // TODO If we have a UNIONED primary expression then it would be possible to just select the DN_TYPE from the particular union
                        throw new NucleusException("Result has call to " + typeExpr + " but contained expression has no discriminator. Not supported");
                    }
                    int[] cols = stmt.select(sqlExpr.getSQLTable(), discrimMapping, null, true);
                    StatementMappingIndex idx = new StatementMappingIndex(discrimMapping);
                    idx.setColumnPositions(cols);
                    resultDefinition.addMappingForResultExpression(i, idx);
                } else {
                    throw new NucleusException("Result has call to " + typeExpr + " but contained expression not supported");
                }
            } else if (resultExprs[i] instanceof CreatorExpression) {
                processCreatorExpression((CreatorExpression) resultExprs[i]);
                NewObjectExpression sqlExpr = (NewObjectExpression) stack.pop();
                StatementNewObjectMapping stmtMap = getStatementMappingForNewObjectExpression(sqlExpr, stmt);
                resultDefinition.addMappingForResultExpression(i, stmtMap);
            } else if (resultExprs[i] instanceof DyadicExpression || resultExprs[i] instanceof CaseExpression) {
                if (unionsPresent) {
                    // Process the first union separately (in case they have TYPE/instanceof) and then handle remaining UNIONs below
                    stmt.setAllowUnions(false);
                }
                resultExprs[i].evaluate(this);
                SQLExpression sqlExpr = stack.pop();
                int[] cols = stmt.select(sqlExpr, alias);
                StatementMappingIndex idx = new StatementMappingIndex(sqlExpr.getJavaTypeMapping());
                idx.setColumnPositions(cols);
                if (alias != null) {
                    resultAliases.add(alias);
                    idx.setColumnAlias(alias);
                }
                resultDefinition.addMappingForResultExpression(i, idx);
                if (unionsPresent) {
                    // Process remaining UNIONs. Assumed that we have the same result mapping as the first UNION otherwise SQL wouldn't work anyway
                    stmt.setAllowUnions(true);
                    List<SelectStatement> unionStmts = stmt.getUnions();
                    SelectStatement originalStmt = stmt;
                    for (SelectStatement unionStmt : unionStmts) {
                        this.stmt = unionStmt;
                        unionStmt.setQueryGenerator(this);
                        unionStmt.setAllowUnions(false);
                        resultExprs[i].evaluate(this);
                        sqlExpr = stack.pop();
                        unionStmt.select(sqlExpr, alias);
                        unionStmt.setQueryGenerator(null);
                        unionStmt.setAllowUnions(true);
                    }
                    this.stmt = originalStmt;
                }
            } else {
                throw new NucleusException("Dont currently support result clause containing expression of type " + resultExprs[i]);
            }
        }
        if (stmt.getNumberOfSelects() == 0) {
            // Nothing selected so likely the user had some "new MyClass()" expression, so select "1"
            stmt.select(exprFactory.newLiteral(stmt, storeMgr.getMappingManager().getMapping(Integer.class), 1), null);
        }
    } else {
        // Select of the candidate (no result)
        if (candidateCmd.getIdentityType() == IdentityType.NONDURABLE) {
            // Nondurable identity cases have no "id" for later fetching so get all fields now
            if (NucleusLogger.QUERY.isDebugEnabled()) {
                NucleusLogger.QUERY.debug(Localiser.msg("052520", candidateCmd.getFullClassName()));
            }
            fetchPlan.setGroup("all");
        }
        if (subclasses) {
        // TODO Check for special case of candidate+subclasses stores in same table with discriminator, so select FetchGroup of subclasses also
        }
        int maxFetchDepth = fetchPlan.getMaxFetchDepth();
        if (maxFetchDepth < 0) {
            NucleusLogger.QUERY.debug("No limit specified on query fetch so limiting to 3 levels from candidate. " + "Specify the '" + PropertyNames.PROPERTY_MAX_FETCH_DEPTH + "' to override this");
            // TODO Arbitrary
            maxFetchDepth = 3;
        }
        // This means that we then cater for a UNION using a different column name than the primary statement
        if (unionsPresent) {
            // Process the first union separately (in case they have TYPE/instanceof) and then handle remaining UNIONs below
            stmt.setAllowUnions(false);
        }
        selectFetchPlanForCandidate(stmt, resultDefinitionForClass, maxFetchDepth);
        if (unionsPresent) {
            // Process remaining UNIONs. Assumed that we have the same result mapping as the first UNION otherwise SQL wouldn't work anyway
            stmt.setAllowUnions(true);
            List<SelectStatement> unionStmts = stmt.getUnions();
            SelectStatement originalStmt = stmt;
            for (SelectStatement unionStmt : unionStmts) {
                this.stmt = unionStmt;
                unionStmt.setQueryGenerator(this);
                unionStmt.setAllowUnions(false);
                // We don't want to overwrite anything in the root StatementClassMapping
                StatementClassMapping dummyResClsMapping = new StatementClassMapping();
                selectFetchPlanForCandidate(unionStmt, dummyResClsMapping, maxFetchDepth);
                unionStmt.setQueryGenerator(null);
                unionStmt.setAllowUnions(true);
            }
            this.stmt = originalStmt;
        }
    }
    compileComponent = null;
}
Also used : SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) FetchPlanForClass(org.datanucleus.FetchPlanForClass) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) CreatorExpression(org.datanucleus.query.expression.CreatorExpression) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) CaseExpression(org.datanucleus.query.expression.CaseExpression) NewObjectExpression(org.datanucleus.store.rdbms.sql.expression.NewObjectExpression) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) TemporalLiteral(org.datanucleus.store.rdbms.sql.expression.TemporalLiteral) SQLLiteral(org.datanucleus.store.rdbms.sql.expression.SQLLiteral) ParameterLiteral(org.datanucleus.store.rdbms.sql.expression.ParameterLiteral) BooleanLiteral(org.datanucleus.store.rdbms.sql.expression.BooleanLiteral) IntegerLiteral(org.datanucleus.store.rdbms.sql.expression.IntegerLiteral) Literal(org.datanucleus.query.expression.Literal) NullLiteral(org.datanucleus.store.rdbms.sql.expression.NullLiteral) ArrayList(java.util.ArrayList) List(java.util.List) InvokeExpression(org.datanucleus.query.expression.InvokeExpression) TypeExpression(org.datanucleus.query.expression.TypeExpression) VariableExpression(org.datanucleus.query.expression.VariableExpression) DyadicExpression(org.datanucleus.query.expression.DyadicExpression) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) CaseExpression(org.datanucleus.query.expression.CaseExpression) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) StringExpression(org.datanucleus.store.rdbms.sql.expression.StringExpression) JoinExpression(org.datanucleus.query.expression.JoinExpression) NumericSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.NumericSubqueryExpression) StringSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.StringSubqueryExpression) ClassExpression(org.datanucleus.query.expression.ClassExpression) InvokeExpression(org.datanucleus.query.expression.InvokeExpression) MapExpression(org.datanucleus.store.rdbms.sql.expression.MapExpression) SubqueryExpression(org.datanucleus.query.expression.SubqueryExpression) NewObjectExpression(org.datanucleus.store.rdbms.sql.expression.NewObjectExpression) TemporalSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.TemporalSubqueryExpression) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) OrderExpression(org.datanucleus.query.expression.OrderExpression) PrimaryExpression(org.datanucleus.query.expression.PrimaryExpression) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) TemporalExpression(org.datanucleus.store.rdbms.sql.expression.TemporalExpression) ArrayExpression(org.datanucleus.query.expression.ArrayExpression) ResultAliasExpression(org.datanucleus.store.rdbms.sql.expression.ResultAliasExpression) CreatorExpression(org.datanucleus.query.expression.CreatorExpression) Expression(org.datanucleus.query.expression.Expression) TypeExpression(org.datanucleus.query.expression.TypeExpression) NumericExpression(org.datanucleus.store.rdbms.sql.expression.NumericExpression) CollectionExpression(org.datanucleus.store.rdbms.sql.expression.CollectionExpression) DyadicExpression(org.datanucleus.query.expression.DyadicExpression) ParameterExpression(org.datanucleus.query.expression.ParameterExpression) ColumnExpression(org.datanucleus.store.rdbms.sql.expression.ColumnExpression) VariableExpression(org.datanucleus.query.expression.VariableExpression) EmbeddedMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedMapping) ClassTable(org.datanucleus.store.rdbms.table.ClassTable) ParameterExpression(org.datanucleus.query.expression.ParameterExpression) NucleusException(org.datanucleus.exceptions.NucleusException) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 18 with UnboundExpression

use of org.datanucleus.store.rdbms.sql.expression.UnboundExpression in project datanucleus-rdbms by datanucleus.

the class MapContainsEntryMethod method containsAsSubquery.

/**
 * Method to return an expression for Map.containsEntry using a subquery "EXISTS".
 * This is for use when there are "!contains" or "OR" operations in the filter.
 * Creates the following SQL,
 * <ul>
 * <li><b>Map using join table</b>
 * <pre>
 * SELECT 1 FROM JOIN_TBL A0_SUB
 * WHERE A0_SUB.JOIN_OWN_ID = A0.ID
 * AND A0_SUB.JOIN_VAL_ID = {valExpr}
 * AND Ao_SUB.JOIN_KEY_ID = {keyExpr}
 * </pre>
 * </li>
 * <li><b>Map with key stored in value</b>
 * <pre>
 * SELECT 1 FROM VAL_TABLE A0_SUB
 * WHERE B0.JOIN_OWN_ID = A0.ID
 * AND A0_SUB.ID = {valExpr}
 * AND A0_SUB.KEY_ID = {keyExpr}
 * </pre>
 * </li>
 * <li><b>Map of value stored in key</b>
 * <pre>
 * SELECT 1 FROM KEY_TABLE A0_SUB
 * WHERE A0_SUB.OWN_ID = A0.ID
 * AND A0_SUB.VAL_ID = {valExpr}
 * AND A0_SUB.ID = {keyExpr}
 * </pre>
 * </li>
 * </ul>
 * and returns a BooleanSubqueryExpression ("EXISTS (subquery)")
 * @param stmt SQLStatement
 * @param mapExpr Map expression
 * @param keyExpr Expression for the key
 * @param valExpr Expression for the value
 * @return Contains expression
 */
protected SQLExpression containsAsSubquery(SQLStatement stmt, MapExpression mapExpr, SQLExpression keyExpr, SQLExpression valExpr) {
    boolean keyIsUnbound = (keyExpr instanceof UnboundExpression);
    String keyVarName = null;
    if (keyIsUnbound) {
        keyVarName = ((UnboundExpression) keyExpr).getVariableName();
        NucleusLogger.QUERY.debug(">> Map.containsEntry binding unbound variable " + keyVarName + " using SUBQUERY");
    // TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
    }
    boolean valIsUnbound = (valExpr instanceof UnboundExpression);
    String valVarName = null;
    if (valIsUnbound) {
        valVarName = ((UnboundExpression) valExpr).getVariableName();
        NucleusLogger.QUERY.debug(">> Map.containsEntry binding unbound variable " + valVarName + " using SUBQUERY");
    // TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
    }
    RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
    SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
    ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
    AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
    AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr);
    AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr);
    MapTable joinTbl = (MapTable) storeMgr.getTable(mmd);
    SelectStatement subStmt = null;
    if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
        // JoinTable Map
        subStmt = new SelectStatement(stmt, storeMgr, joinTbl, null, null);
        subStmt.setClassLoaderResolver(clr);
        JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
        subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
        // Restrict to collection owner
        JavaTypeMapping ownerMapping = ((JoinTable) joinTbl).getOwnerMapping();
        SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
        SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
        subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
        SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getValueMapping());
        if (valIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to value TODO Add join to valueTbl if present
            subStmt.whereAnd(valIdExpr.eq(valExpr), true);
        }
        SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getKeyMapping());
        if (keyIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to key TODO Add join to keyTbl if present
            subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
        }
    } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
        // Key stored in value table
        DatastoreClass valTbl = storeMgr.getDatastoreClass(mmd.getMap().getValueType(), clr);
        AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(mmd.getKeyMetaData().getMappedBy());
        subStmt = new SelectStatement(stmt, storeMgr, valTbl, null, null);
        subStmt.setClassLoaderResolver(clr);
        JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
        subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
        // Restrict to map owner (on value table)
        JavaTypeMapping ownerMapping = null;
        if (mmd.getMappedBy() != null) {
            ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
        } else {
            ownerMapping = valTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
        }
        SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
        SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
        subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
        SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getIdMapping());
        if (valIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to value
            subStmt.whereAnd(valIdExpr.eq(valExpr), true);
        }
        SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valTbl.getMemberMapping(valKeyMmd));
        if (keyIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to key TODO Add join to keyTbl if present
            subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
        }
    } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
        DatastoreClass keyTbl = storeMgr.getDatastoreClass(mmd.getMap().getKeyType(), clr);
        JavaTypeMapping ownerMapping = null;
        if (mmd.getMappedBy() != null) {
            ownerMapping = keyTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
        } else {
            ownerMapping = keyTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
        }
        AbstractMemberMetaData keyValMmd = keyCmd.getMetaDataForMember(mmd.getValueMetaData().getMappedBy());
        subStmt = new SelectStatement(stmt, storeMgr, keyTbl, null, null);
        subStmt.setClassLoaderResolver(clr);
        JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
        subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
        // Restrict to map owner (on key table)
        SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
        SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping());
        subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
        SQLExpression valIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyTbl.getMemberMapping(keyValMmd));
        if (valIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to value TODO Add join to valTbl if present
            subStmt.whereAnd(valIdExpr.eq(valExpr), true);
        }
        JavaTypeMapping keyMapping = keyTbl.getIdMapping();
        SQLExpression keyIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyMapping);
        if (keyIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to key
            subStmt.whereAnd(keyIdExpr.eq(keyExpr), true);
        }
    }
    return new BooleanSubqueryExpression(stmt, "EXISTS", subStmt);
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) MapTable(org.datanucleus.store.rdbms.table.MapTable) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) JoinTable(org.datanucleus.store.rdbms.table.JoinTable)

Example 19 with UnboundExpression

use of org.datanucleus.store.rdbms.sql.expression.UnboundExpression in project datanucleus-rdbms by datanucleus.

the class MapContainsEntryMethod method containsAsInnerJoin.

/**
 * Method to return an expression for Map.containsEntry using INNER JOIN to the element.
 * This is only for use when there are no "!containsEntry" and no "OR" operations.
 * Creates SQL by adding INNER JOIN to the join table (where it exists), and also to the value table
 * adding an AND condition on the value (with value of the valueExpr).
 * Returns a BooleanExpression "TRUE" (since the INNER JOIN will guarantee if the entry is
 * contained of not).
 * @param stmt SQLStatement
 * @param mapExpr Map expression
 * @param keyExpr Expression for the key
 * @param valExpr Expression for the value
 * @return Contains expression
 */
protected SQLExpression containsAsInnerJoin(SQLStatement stmt, MapExpression mapExpr, SQLExpression keyExpr, SQLExpression valExpr) {
    boolean keyIsUnbound = (keyExpr instanceof UnboundExpression);
    String keyVarName = null;
    if (keyIsUnbound) {
        keyVarName = ((UnboundExpression) keyExpr).getVariableName();
        NucleusLogger.QUERY.debug(">> Map.containsEntry binding unbound variable " + keyVarName + " using INNER JOIN");
    // TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
    }
    boolean valIsUnbound = (valExpr instanceof UnboundExpression);
    String valVarName = null;
    if (valIsUnbound) {
        valVarName = ((UnboundExpression) valExpr).getVariableName();
        NucleusLogger.QUERY.debug(">> Map.containsEntry binding unbound variable " + valVarName + " using INNER JOIN");
    // TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
    }
    RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
    SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
    ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
    AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
    AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr);
    AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr);
    if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
        // Map formed in join table - add join to join table, then to key/value tables (if present)
        MapTable mapTbl = (MapTable) storeMgr.getTable(mmd);
        SQLTable joinSqlTbl = stmt.join(JoinType.INNER_JOIN, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), mapTbl, null, mapTbl.getOwnerMapping(), null, null);
        if (valCmd != null) {
            DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr);
            SQLTable valSqlTbl = stmt.join(JoinType.INNER_JOIN, joinSqlTbl, mapTbl.getValueMapping(), valTbl, null, valTbl.getIdMapping(), null, null);
            SQLExpression valIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping());
            if (valIsUnbound) {
                // Bind the variable in the QueryGenerator
                stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
            } else {
                // Add restrict to value
                stmt.whereAnd(valIdExpr.eq(valExpr), true);
            }
        } else {
            SQLExpression valIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getValueMapping());
            if (valIsUnbound) {
                // Bind the variable in the QueryGenerator
                stmt.getQueryGenerator().bindVariable(valVarName, null, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
            } else {
                // Add restrict to value
                stmt.whereAnd(valIdExpr.eq(valExpr), true);
            }
        }
        if (keyCmd != null) {
            DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
            SQLTable keySqlTbl = stmt.join(JoinType.INNER_JOIN, joinSqlTbl, mapTbl.getKeyMapping(), keyTbl, null, keyTbl.getIdMapping(), null, null);
            SQLExpression keyIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
            if (keyIsUnbound) {
                // Bind the variable in the QueryGenerator
                stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
            } else {
                // Add restrict to key
                stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
            }
        } else {
            SQLExpression keyIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getKeyMapping());
            if (keyIsUnbound) {
                // Bind the variable in the QueryGenerator
                stmt.getQueryGenerator().bindVariable(keyVarName, null, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
            } else {
                // Add restrict to key
                stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
            }
        }
    } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
        // Map formed in value table - add join to value table, then to key table (if present)
        DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr);
        JavaTypeMapping ownerMapping = null;
        if (mmd.getMappedBy() != null) {
            ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
        } else {
            ownerMapping = valTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
        }
        SQLTable valSqlTbl = stmt.join(JoinType.INNER_JOIN, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), valTbl, null, ownerMapping, null, null);
        SQLExpression valIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping());
        if (valIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to value
            stmt.whereAnd(valIdExpr.eq(valExpr), true);
        }
        if (keyCmd != null) {
            // Add inner join to key table
            AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(mmd.getKeyMetaData().getMappedBy());
            DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
            SQLTable keySqlTbl = stmt.join(JoinType.INNER_JOIN, valSqlTbl, valTbl.getMemberMapping(valKeyMmd), keyTbl, null, keyTbl.getIdMapping(), null, null);
            SQLExpression keyIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
            if (keyIsUnbound) {
                // Bind the variable in the QueryGenerator
                stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
            } else {
                // Add restriction to key
                stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
            }
        } else {
            AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(mmd.getKeyMetaData().getMappedBy());
            SQLExpression keyIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getMemberMapping(valKeyMmd));
            if (keyIsUnbound) {
                // Bind the variable in the QueryGenerator
                stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
            } else {
                // Add restriction to key
                stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
            }
        }
    } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
        // Map formed in key table - add join to key table then to value table (if present)
        DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
        AbstractMemberMetaData keyValMmd = keyCmd.getMetaDataForMember(mmd.getValueMetaData().getMappedBy());
        JavaTypeMapping ownerMapping = null;
        if (mmd.getMappedBy() != null) {
            ownerMapping = keyTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
        } else {
            ownerMapping = keyTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
        }
        SQLTable keySqlTbl = stmt.join(JoinType.INNER_JOIN, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), keyTbl, null, ownerMapping, null, null);
        SQLExpression keyIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
        if (keyIsUnbound) {
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(keyVarName, keyCmd, keyIdExpr.getSQLTable(), keyIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to key
            stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
        }
        if (valCmd != null) {
            // Add inner join to value table
            DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr);
            SQLTable valSqlTbl = stmt.join(JoinType.INNER_JOIN, keySqlTbl, keyTbl.getMemberMapping(keyValMmd), valTbl, null, valTbl.getIdMapping(), null, null);
            SQLExpression valIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getIdMapping());
            if (valIsUnbound) {
                // Bind the variable in the QueryGenerator
                stmt.getQueryGenerator().bindVariable(valVarName, valCmd, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
            } else {
                // Add restrict to value
                stmt.whereAnd(valIdExpr.eq(valExpr), true);
            }
        } else {
            SQLExpression valIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getMemberMapping(keyValMmd));
            if (valIsUnbound) {
                // Bind the variable in the QueryGenerator
                stmt.getQueryGenerator().bindVariable(valVarName, null, valIdExpr.getSQLTable(), valIdExpr.getJavaTypeMapping());
            } else {
                // Add restrict to value
                stmt.whereAnd(valIdExpr.eq(valExpr), true);
            }
        }
    }
    JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
    return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) MapTable(org.datanucleus.store.rdbms.table.MapTable) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 20 with UnboundExpression

use of org.datanucleus.store.rdbms.sql.expression.UnboundExpression in project datanucleus-rdbms by datanucleus.

the class MapContainsKeyMethod method containsAsJoin.

/**
 * Method to return an expression for Map.containsKey using INNER JOIN to the element.
 * This is only for use when there are no "!containsKey" and no "OR" operations.
 * Creates SQL by adding INNER JOIN to the join table (where it exists), and also to the key table
 * adding an AND condition on the element (with value of the keyExpr).
 * Returns a BooleanExpression "TRUE" (since the INNER JOIN will guarantee if the key is contained of not).
 * @param stmt SQLStatement
 * @param mapExpr Map expression
 * @param keyExpr Expression for the key
 * @param joinType Type of join
 * @return Contains expression
 */
protected SQLExpression containsAsJoin(SQLStatement stmt, MapExpression mapExpr, SQLExpression keyExpr, JoinType joinType) {
    boolean keyIsUnbound = (keyExpr instanceof UnboundExpression);
    String varName = null;
    String keyAlias = null;
    if (keyIsUnbound) {
        varName = ((UnboundExpression) keyExpr).getVariableName();
        NucleusLogger.QUERY.debug("map.containsKey(" + keyExpr + ") binding unbound variable " + varName + " using INNER JOIN");
    // TODO What if the variable is declared as a subtype, handle this see CollectionContainsMethod
    } else if (!stmt.getQueryGenerator().hasExplicitJoins()) {
        if (stmt.getJoinTypeForTable(keyExpr.getSQLTable()) == JoinType.CROSS_JOIN) {
            keyAlias = stmt.removeCrossJoin(keyExpr.getSQLTable());
            keyIsUnbound = true;
            NucleusLogger.QUERY.debug("map.containsKey(" + keyExpr + ") was previously bound as CROSS JOIN but changing to INNER JOIN");
        }
    }
    RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
    SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
    ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
    AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
    AbstractClassMetaData keyCmd = mmd.getMap().getKeyClassMetaData(clr);
    if (mmd.getMap().getMapType() == MapType.MAP_TYPE_JOIN) {
        // Map formed in join table - add join to join table, then to key table (if present)
        MapTable mapTbl = (MapTable) storeMgr.getTable(mmd);
        SQLTable joinSqlTbl = stmt.join(joinType, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), mapTbl, null, mapTbl.getOwnerMapping(), null, null);
        if (keyCmd != null) {
            if (keyIsUnbound) {
                DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
                SQLTable keySqlTbl = stmt.join(joinType, joinSqlTbl, mapTbl.getKeyMapping(), keyTbl, keyAlias, keyTbl.getIdMapping(), null, null);
                // Bind the variable in the QueryGenerator
                keyExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
                stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
            } else {
                // Add restrict to key
                SQLExpression keyIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getKeyMapping());
                stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
            }
        } else {
            if (keyIsUnbound) {
                // Bind the variable in the QueryGenerator
                keyExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getKeyMapping());
                stmt.getQueryGenerator().bindVariable(varName, null, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
            } else {
                // Add restrict to key
                SQLExpression keyIdExpr = exprFactory.newExpression(stmt, joinSqlTbl, mapTbl.getKeyMapping());
                stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
            }
        }
    } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
        // Map formed in value table - add join to value table, then to key table
        AbstractClassMetaData valCmd = mmd.getMap().getValueClassMetaData(clr);
        DatastoreClass valTbl = storeMgr.getDatastoreClass(valCmd.getFullClassName(), clr);
        AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(mmd.getKeyMetaData().getMappedBy());
        JavaTypeMapping ownerMapping = null;
        if (mmd.getMappedBy() != null) {
            ownerMapping = valTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
        } else {
            ownerMapping = valTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
        }
        SQLTable valSqlTbl = stmt.join(joinType, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), valTbl, null, ownerMapping, null, null);
        if (keyCmd != null) {
            DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
            SQLTable keySqlTbl = stmt.join(joinType, valSqlTbl, valTbl.getMemberMapping(valKeyMmd), keyTbl, keyAlias, keyTbl.getIdMapping(), null, null);
            if (keyIsUnbound) {
                // Bind the variable in the QueryGenerator
                keyExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
                stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
            } else {
                // Add restrict to key
                SQLExpression keyIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
                stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
            }
        } else {
            if (keyIsUnbound) {
                // Bind the variable in the QueryGenerator
                keyExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getMemberMapping(valKeyMmd));
                stmt.getQueryGenerator().bindVariable(varName, null, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
            } else {
                // Add restrict to key
                SQLExpression keyIdExpr = exprFactory.newExpression(stmt, valSqlTbl, valTbl.getMemberMapping(valKeyMmd));
                stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
            }
        }
    } else if (mmd.getMap().getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
        // Map formed in key table - add join to key table
        DatastoreClass keyTbl = storeMgr.getDatastoreClass(keyCmd.getFullClassName(), clr);
        JavaTypeMapping ownerMapping = null;
        if (mmd.getMappedBy() != null) {
            ownerMapping = keyTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
        } else {
            ownerMapping = keyTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
        }
        SQLTable keySqlTbl = stmt.join(joinType, mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(), keyTbl, keyAlias, ownerMapping, null, null);
        if (keyIsUnbound) {
            // Bind the variable in the QueryGenerator
            keyExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
            stmt.getQueryGenerator().bindVariable(varName, keyCmd, keyExpr.getSQLTable(), keyExpr.getJavaTypeMapping());
        } else {
            // Add restrict to key
            SQLExpression keyIdExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTbl.getIdMapping());
            stmt.whereAnd(keyIdExpr.eq(keyExpr), true);
        }
    }
    JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
    return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) MapTable(org.datanucleus.store.rdbms.table.MapTable) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)24 UnboundExpression (org.datanucleus.store.rdbms.sql.expression.UnboundExpression)24 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)18 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)15 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)14 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)13 BooleanExpression (org.datanucleus.store.rdbms.sql.expression.BooleanExpression)13 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)13 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)12 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)10 NucleusException (org.datanucleus.exceptions.NucleusException)9 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)9 ParameterLiteral (org.datanucleus.store.rdbms.sql.expression.ParameterLiteral)9 BooleanSubqueryExpression (org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression)8 MapTable (org.datanucleus.store.rdbms.table.MapTable)7 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)6 MapExpression (org.datanucleus.store.rdbms.sql.expression.MapExpression)6 NumericExpression (org.datanucleus.store.rdbms.sql.expression.NumericExpression)6 SQLLiteral (org.datanucleus.store.rdbms.sql.expression.SQLLiteral)6 StringExpression (org.datanucleus.store.rdbms.sql.expression.StringExpression)6