Search in sources :

Example 26 with SelectStatement

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

the class RDBMSStoreHelper method getClassNameForIdUsingUnion.

/**
 * Utility that does a union candidate query for the specified candidate(s) and subclasses
 * and returns the class name of the instance that has the specified identity (if any).
 * @param storeMgr RDBMS StoreManager
 * @param ec execution context
 * @param id The id
 * @param rootCmds Metadata for the classes at the root
 * @return Name of the class with this identity (or null if none found)
 */
public static String getClassNameForIdUsingUnion(RDBMSStoreManager storeMgr, ExecutionContext ec, Object id, List<AbstractClassMetaData> rootCmds) {
    // Check for input error
    if (rootCmds == null || rootCmds.isEmpty() || id == null) {
        return null;
    }
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    // Form a query UNIONing all possible root candidates (and their subclasses)
    Iterator<AbstractClassMetaData> rootCmdIter = rootCmds.iterator();
    // Metadata for sample class in the tree so we can check if needs locking
    AbstractClassMetaData sampleCmd = null;
    SelectStatement sqlStmtMain = null;
    while (rootCmdIter.hasNext()) {
        AbstractClassMetaData rootCmd = rootCmdIter.next();
        DatastoreClass rootTbl = storeMgr.getDatastoreClass(rootCmd.getFullClassName(), clr);
        InheritanceMetaData rootInhmd = rootCmd.getBaseAbstractClassMetaData().getInheritanceMetaData();
        if (rootInhmd.getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
            // COMPLETE TABLE so use one branch of UNION for each possible class
            if (rootTbl != null) {
                UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, clr.classForName(rootCmd.getFullClassName()), false, null, null);
                stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                if (sqlStmtMain == null) {
                    sampleCmd = rootCmd;
                    sqlStmtMain = stmtGen.getStatement(ec);
                    // WHERE (object id) = ?
                    JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping();
                    JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                    SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping);
                    SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID");
                    sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true);
                } else {
                    SelectStatement sqlStmt = stmtGen.getStatement(ec);
                    // WHERE (object id) = ?
                    JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
                    JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                    SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
                    SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
                    sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true);
                    sqlStmtMain.union(sqlStmt);
                }
            }
            Collection<String> rootSubclassNames = storeMgr.getSubClassesForClass(rootCmd.getFullClassName(), true, clr);
            for (String rootSubclassName : rootSubclassNames) {
                AbstractClassMetaData rootSubclassCmd = storeMgr.getMetaDataManager().getMetaDataForClass(rootSubclassName, clr);
                DatastoreClass rootSubclassTbl = storeMgr.getDatastoreClass(rootSubclassCmd.getFullClassName(), clr);
                if (rootSubclassTbl != null) {
                    UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, clr.classForName(rootSubclassCmd.getFullClassName()), false, null, null);
                    stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                    if (sqlStmtMain == null) {
                        sampleCmd = rootSubclassCmd;
                        sqlStmtMain = stmtGen.getStatement(ec);
                        // WHERE (object id) = ?
                        JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping();
                        JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                        SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping);
                        SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID");
                        sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true);
                    } else {
                        SelectStatement sqlStmt = stmtGen.getStatement(ec);
                        // WHERE (object id) = ?
                        JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
                        JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                        SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
                        SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
                        sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true);
                        sqlStmtMain.union(sqlStmt);
                    }
                }
            }
            continue;
        }
        if (rootTbl == null) {
            // Class must be using "subclass-table" (no table of its own) so find where it is
            AbstractClassMetaData[] subcmds = storeMgr.getClassesManagingTableForClass(rootCmd, clr);
            if (subcmds == null || subcmds.length == 0) {
            // No table for this class so ignore
            } else {
                for (int i = 0; i < subcmds.length; i++) {
                    UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, clr.classForName(subcmds[i].getFullClassName()), true, null, null);
                    stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                    if (sqlStmtMain == null) {
                        sampleCmd = subcmds[i];
                        sqlStmtMain = stmtGen.getStatement(ec);
                        // WHERE (object id) = ?
                        JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping();
                        JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                        SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping);
                        SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID");
                        sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true);
                    } else {
                        SelectStatement sqlStmt = stmtGen.getStatement(ec);
                        // WHERE (object id) = ?
                        JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
                        JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                        SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
                        SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
                        sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true);
                        sqlStmtMain.union(sqlStmt);
                    }
                }
            }
        } else {
            UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, clr.classForName(rootCmd.getFullClassName()), true, null, null);
            stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
            if (sqlStmtMain == null) {
                sampleCmd = rootCmd;
                sqlStmtMain = stmtGen.getStatement(ec);
                // WHERE (object id) = ?
                JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping();
                JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping);
                SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID");
                sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true);
            } else {
                SelectStatement sqlStmt = stmtGen.getStatement(ec);
                // WHERE (object id) = ?
                JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
                JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
                SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
                sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true);
                sqlStmtMain.union(sqlStmt);
            }
        }
    }
    // Perform the query
    if (sqlStmtMain != null) {
        try {
            ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            if (sampleCmd != null && ec.getSerializeReadForClass(sampleCmd.getFullClassName())) {
                sqlStmtMain.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
            }
            try {
                PreparedStatement ps = SQLStatementHelper.getPreparedStatementForSQLStatement(sqlStmtMain, ec, mconn, null, null);
                String statement = sqlStmtMain.getSQLText().toSQL();
                try {
                    ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps);
                    try {
                        while (rs.next()) {
                            try {
                                return rs.getString(UnionStatementGenerator.DN_TYPE_COLUMN).trim();
                            } catch (SQLException sqle) {
                            }
                        }
                    } finally {
                        rs.close();
                    }
                } finally {
                    sqlControl.closeStatement(mconn, ps);
                }
            } finally {
                mconn.release();
            }
        } catch (SQLException sqe) {
            NucleusLogger.DATASTORE.error("Exception with UNION statement", sqe);
            throw new NucleusDataStoreException(sqe.toString());
        }
    }
    return null;
}
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) SQLException(java.sql.SQLException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) PreparedStatement(java.sql.PreparedStatement) PersistableIdMapping(org.datanucleus.store.rdbms.mapping.java.PersistableIdMapping) InheritanceMetaData(org.datanucleus.metadata.InheritanceMetaData) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) UnionStatementGenerator(org.datanucleus.store.rdbms.sql.UnionStatementGenerator) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass)

Example 27 with SelectStatement

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

the class QueryToSQLMapper method compile.

/**
 * Method to update the supplied SQLStatement with the components of the specified query.
 * During the compilation process this updates the SQLStatement "compileComponent" to the
 * component of the query being compiled.
 */
public void compile() {
    if (NucleusLogger.QUERY.isDebugEnabled() && parentMapper == null) {
        // Give debug output of compilation
        StringBuilder str = new StringBuilder("JoinType : navigation(default=");
        str.append(defaultJoinType != null ? defaultJoinType : "(using nullability)");
        str.append(", filter=");
        str.append(defaultJoinTypeFilter != null ? defaultJoinTypeFilter : "(using nullability)");
        str.append(")");
        if (extensionsByName != null) {
            Iterator<Map.Entry<String, Object>> extensionsIter = extensionsByName.entrySet().iterator();
            while (extensionsIter.hasNext()) {
                Map.Entry<String, Object> entry = extensionsIter.next();
                String key = entry.getKey();
                if (key.startsWith("datanucleus.query.jdoql.") && key.endsWith(".join")) {
                    // Alias join definition
                    String alias = key.substring("datanucleus.query.jdoql.".length(), key.lastIndexOf(".join"));
                    str.append(", ").append(alias).append("=").append(entry.getValue());
                }
            }
        }
        NucleusLogger.QUERY.debug("Compile of " + compilation.getQueryLanguage() + " into SQL - " + str);
    }
    compileFrom();
    compileFilter();
    if (stmt instanceof UpdateStatement) {
        compileUpdate((UpdateStatement) stmt);
    } else if (stmt instanceof SelectStatement) {
        SelectStatement selectStmt = (SelectStatement) stmt;
        // the datastore doesn't allow select of some field types when used with DISTINCT
        if (compilation.getResultDistinct()) {
            selectStmt.setDistinct(true);
        } else if (!options.contains(OPTION_EXPLICIT_JOINS) && compilation.getExprResult() == null) {
            // Joins are made implicitly and no result so set distinct based on whether joining to other table groups
            if (selectStmt.getNumberOfTableGroups() > 1) {
                // Queries against an extent always consider only distinct candidate instances, regardless of whether distinct is specified (JDO spec)
                if (!options.contains(OPTION_NON_DISTINCT_IMPLICIT_JOINS)) {
                    // If user can guarantee distinct w/ query no reason to take performance hit of distinct clause
                    selectStmt.setDistinct(true);
                }
            }
        }
        compileResult(selectStmt);
        compileGrouping(selectStmt);
        compileHaving(selectStmt);
        compileOrdering(selectStmt);
    }
    // Check for variables that haven't been bound to the query (declared but not used)
    for (String symbol : compilation.getSymbolTable().getSymbolNames()) {
        Symbol sym = compilation.getSymbolTable().getSymbol(symbol);
        if (sym.getType() == Symbol.VARIABLE) {
            if (compilation.getCompilationForSubquery(sym.getQualifiedName()) == null && !hasSQLTableMappingForAlias(sym.getQualifiedName())) {
                // Variable not a subquery, nor had its table allocated
                throw new QueryCompilerSyntaxException("Query has variable \"" + sym.getQualifiedName() + "\" which is not bound to the query");
            }
        }
    }
}
Also used : SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) UpdateStatement(org.datanucleus.store.rdbms.sql.UpdateStatement) Symbol(org.datanucleus.query.compiler.Symbol) QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException) Map(java.util.Map) HashMap(java.util.HashMap)

Example 28 with SelectStatement

use of org.datanucleus.store.rdbms.sql.SelectStatement 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 29 with SelectStatement

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

the class RDBMSQueryUtils method getStatementForCandidates.

/**
 * Method to return a statement selecting the candidate table(s) required to cover all possible types for this candidates inheritance strategy.
 * @param storeMgr RDBMS StoreManager
 * @param parentStmt Parent statement (if there is one)
 * @param cmd Metadata for the class
 * @param clsMapping Mapping for the results of the statement
 * @param ec ExecutionContext
 * @param candidateCls Candidate class
 * @param subclasses Whether to create a statement for subclasses of the candidate too
 * @param result The result clause
 * @param candidateAlias alias for the candidate (if any)
 * @param candidateTableGroupName TableGroup name for the candidate (if any)
 * @param options Any options for the statement for getting candidates. See SelectStatementGenerator for some options.
 * @return The SQLStatement
 * @throws NucleusException if there are no tables for concrete classes in this query (hence would return null)
 */
public static SelectStatement getStatementForCandidates(RDBMSStoreManager storeMgr, SQLStatement parentStmt, AbstractClassMetaData cmd, StatementClassMapping clsMapping, ExecutionContext ec, Class candidateCls, boolean subclasses, String result, String candidateAlias, String candidateTableGroupName, Set<String> options) {
    SelectStatement stmt = null;
    DatastoreIdentifier candidateAliasId = null;
    if (candidateAlias != null) {
        candidateAliasId = storeMgr.getIdentifierFactory().newTableIdentifier(candidateAlias);
    }
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    List<DatastoreClass> candidateTables = new ArrayList<>();
    if (cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
        DatastoreClass candidateTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr);
        if (candidateTable != null) {
            candidateTables.add(candidateTable);
        }
        if (subclasses) {
            Collection<String> subclassNames = storeMgr.getSubClassesForClass(cmd.getFullClassName(), subclasses, clr);
            if (subclassNames != null) {
                Iterator<String> subclassIter = subclassNames.iterator();
                while (subclassIter.hasNext()) {
                    String subclassName = subclassIter.next();
                    DatastoreClass tbl = storeMgr.getDatastoreClass(subclassName, clr);
                    if (tbl != null) {
                        candidateTables.add(tbl);
                    }
                }
            }
        }
        Iterator<DatastoreClass> iter = candidateTables.iterator();
        int maxClassNameLength = cmd.getFullClassName().length();
        while (iter.hasNext()) {
            DatastoreClass cls = iter.next();
            String className = cls.getType();
            if (className.length() > maxClassNameLength) {
                maxClassNameLength = className.length();
            }
        }
        iter = candidateTables.iterator();
        while (iter.hasNext()) {
            DatastoreClass cls = iter.next();
            SelectStatement tblStmt = new SelectStatement(parentStmt, storeMgr, cls, candidateAliasId, candidateTableGroupName);
            tblStmt.setClassLoaderResolver(clr);
            tblStmt.setCandidateClassName(cls.getType());
            // Add SELECT of dummy column accessible as "DN_TYPE" containing the classname
            JavaTypeMapping m = storeMgr.getMappingManager().getMapping(String.class);
            String nuctypeName = cls.getType();
            if (maxClassNameLength > nuctypeName.length()) {
                nuctypeName = StringUtils.leftAlignedPaddedString(nuctypeName, maxClassNameLength);
            }
            StringLiteral lit = new StringLiteral(tblStmt, m, nuctypeName, null);
            tblStmt.select(lit, UnionStatementGenerator.DN_TYPE_COLUMN);
            if (stmt == null) {
                stmt = tblStmt;
            } else {
                stmt.union(tblStmt);
            }
        }
        if (clsMapping != null) {
            clsMapping.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
        }
    } else {
        // "new-table", "superclass-table", "subclass-table"
        List<Class> candidateClasses = new ArrayList<>();
        if (ClassUtils.isReferenceType(candidateCls)) {
            // Persistent interface, so find all persistent implementations
            String[] clsNames = storeMgr.getNucleusContext().getMetaDataManager().getClassesImplementingInterface(candidateCls.getName(), clr);
            for (int i = 0; i < clsNames.length; i++) {
                Class cls = clr.classForName(clsNames[i]);
                DatastoreClass table = storeMgr.getDatastoreClass(clsNames[i], clr);
                candidateClasses.add(cls);
                candidateTables.add(table);
                AbstractClassMetaData implCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(cls, clr);
                if (implCmd.getIdentityType() != cmd.getIdentityType()) {
                    throw new NucleusUserException("You are querying an interface (" + cmd.getFullClassName() + ") " + "yet one of its implementations (" + implCmd.getFullClassName() + ") uses a different identity type!");
                } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
                    if (cmd.getPKMemberPositions().length != implCmd.getPKMemberPositions().length) {
                        throw new NucleusUserException("You are querying an interface (" + cmd.getFullClassName() + ") " + "yet one of its implementations (" + implCmd.getFullClassName() + ") has a different number of PK members!");
                    }
                }
            }
        } else {
            DatastoreClass candidateTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr);
            if (candidateTable != null) {
                // Candidate has own table
                candidateClasses.add(candidateCls);
                candidateTables.add(candidateTable);
            } else {
                // Candidate stored in subclass tables
                AbstractClassMetaData[] cmds = storeMgr.getClassesManagingTableForClass(cmd, clr);
                if (cmds != null && cmds.length > 0) {
                    for (int i = 0; i < cmds.length; i++) {
                        DatastoreClass table = storeMgr.getDatastoreClass(cmds[i].getFullClassName(), clr);
                        Class cls = clr.classForName(cmds[i].getFullClassName());
                        candidateClasses.add(cls);
                        candidateTables.add(table);
                    }
                } else {
                    throw new UnsupportedOperationException("No tables for query of " + cmd.getFullClassName());
                }
            }
        }
        for (int i = 0; i < candidateTables.size(); i++) {
            DatastoreClass tbl = candidateTables.get(i);
            Class cls = candidateClasses.get(i);
            SelectStatementGenerator stmtGen = null;
            if (tbl.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true) != null || QueryUtils.resultHasOnlyAggregates(result)) {
                // Either has a discriminator, or only selecting aggregates so need single select
                // TODO Add option to omit discriminator restriction
                stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, cls, subclasses, candidateAliasId, candidateTableGroupName);
                stmtGen.setOption(SelectStatementGenerator.OPTION_RESTRICT_DISCRIM);
                if (options != null) {
                    for (String option : options) {
                        stmtGen.setOption(option);
                    }
                }
            } else {
                // No discriminator, so try to identify using UNIONs (hopefully one per class)
                stmtGen = new UnionStatementGenerator(storeMgr, clr, cls, subclasses, candidateAliasId, candidateTableGroupName);
                if (options != null) {
                    for (String option : options) {
                        stmtGen.setOption(option);
                    }
                }
                if (result == null) {
                    // Returning one row per candidate so include distinguisher column
                    stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                    if (clsMapping != null) {
                        clsMapping.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
                    }
                }
            }
            stmtGen.setParentStatement(parentStmt);
            SelectStatement tblStmt = stmtGen.getStatement(ec);
            if (stmt == null) {
                stmt = tblStmt;
            } else {
                stmt.union(tblStmt);
            }
        }
    }
    return stmt;
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) ArrayList(java.util.ArrayList) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) UnionStatementGenerator(org.datanucleus.store.rdbms.sql.UnionStatementGenerator) SelectStatementGenerator(org.datanucleus.store.rdbms.sql.SelectStatementGenerator) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) StringLiteral(org.datanucleus.store.rdbms.sql.expression.StringLiteral) DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) DiscriminatorStatementGenerator(org.datanucleus.store.rdbms.sql.DiscriminatorStatementGenerator) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass)

Example 30 with SelectStatement

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

the class FKSetStore method getIteratorStatement.

/**
 * Method to return the SQLStatement and mapping for an iterator for this backing store.
 * Create a statement of the form
 * <pre>
 * SELECT ELEM_COLS
 * FROM ELEM_TBL
 * [WHERE]
 *   [ELEM_TBL.OWNER_ID = {value}] [AND]
 *   [ELEM_TBL.DISCRIM = {discrimValue}]
 * [ORDER BY {orderClause}]
 * </pre>
 * @param ec ExecutionContext
 * @param fp FetchPlan to use in determining which fields of element to select
 * @param addRestrictionOnOwner Whether to restrict to a particular owner (otherwise functions as bulk fetch for many owners).
 * @return The SQLStatement and its associated StatementClassMapping
 */
public IteratorStatement getIteratorStatement(ExecutionContext ec, FetchPlan fp, boolean addRestrictionOnOwner) {
    SelectStatement sqlStmt = null;
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    StatementClassMapping iteratorMappingClass = new StatementClassMapping();
    if (elementInfo[0].getDatastoreClass().getDiscriminatorMetaData() != null && elementInfo[0].getDatastoreClass().getDiscriminatorMetaData().getStrategy() != DiscriminatorStrategy.NONE) {
        // TODO Only caters for one elementInfo, but with subclass-table we can have multiple
        String elementType = ownerMemberMetaData.getCollection().getElementType();
        if (ClassUtils.isReferenceType(clr.classForName(elementType))) {
            String[] clsNames = storeMgr.getNucleusContext().getMetaDataManager().getClassesImplementingInterface(elementType, clr);
            Class[] cls = new Class[clsNames.length];
            for (int i = 0; i < clsNames.length; i++) {
                cls[i] = clr.classForName(clsNames[i]);
            }
            sqlStmt = new DiscriminatorStatementGenerator(storeMgr, clr, cls, true, null, null).getStatement(ec);
        } else {
            sqlStmt = new DiscriminatorStatementGenerator(storeMgr, clr, clr.classForName(elementInfo[0].getClassName()), true, null, null).getStatement(ec);
        }
        iterateUsingDiscriminator = true;
        // TODO Cater for having all possible subclasses stored in the same table (so we can select their fields too)
        // String[] elemSubclasses = op.getExecutionContext().getMetaDataManager().getSubclassesForClass(emd.getFullClassName(), false);
        // NucleusLogger.GENERAL.info(">> FKSetStore.iter iterMapDef=" + iteratorMappingDef + " table=" + sqlStmt.getPrimaryTable() +
        // " emd=" + emd.getFullClassName() + " elem.subclasses=" + StringUtils.objectArrayToString(elemSubclasses));
        // Select the required fields (of the element class)
        SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, iteratorMappingClass, fp, sqlStmt.getPrimaryTable(), elementCmd, fp.getMaxFetchDepth());
    } else {
        boolean selectFetchPlan = true;
        Class elementTypeCls = clr.classForName(elementType);
        if (elementTypeCls.isInterface() && elementInfo.length > 1) {
            // Multiple implementations of an interface, so assume the FetchPlan differs between implementation
            selectFetchPlan = false;
        }
        // TODO This only works if the different elementInfos have the same number of PK fields (otherwise get SQL error in UNION)
        for (int i = 0; i < elementInfo.length; i++) {
            final Class elementCls = clr.classForName(this.elementInfo[i].getClassName());
            UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, elementCls, true, null, null);
            stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
            iteratorMappingClass.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
            SelectStatement subStmt = stmtGen.getStatement(ec);
            if (selectFetchPlan) {
                // Select the FetchPlan fields (of the element class)
                if (sqlStmt == null) {
                    SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(subStmt, iteratorMappingClass, fp, subStmt.getPrimaryTable(), elementInfo[i].getAbstractClassMetaData(), fp.getMaxFetchDepth());
                } else {
                    SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(subStmt, null, fp, subStmt.getPrimaryTable(), elementInfo[i].getAbstractClassMetaData(), fp.getMaxFetchDepth());
                }
            } else {
                // Select the candidate id of the element class only
                if (sqlStmt == null) {
                    SQLStatementHelper.selectIdentityOfCandidateInStatement(subStmt, iteratorMappingClass, elementInfo[i].getAbstractClassMetaData());
                } else {
                    SQLStatementHelper.selectIdentityOfCandidateInStatement(subStmt, null, elementInfo[i].getAbstractClassMetaData());
                }
            }
            if (sqlStmt == null) {
                sqlStmt = subStmt;
            } else {
                sqlStmt.union(subStmt);
            }
        }
        if (sqlStmt == null) {
            throw new NucleusException("Unable to generate iterator statement for field " + getOwnerMemberMetaData().getFullFieldName());
        }
    }
    if (addRestrictionOnOwner) {
        // Apply condition to filter by owner
        // TODO If ownerMapping is not for containerTable then do JOIN to ownerTable in the FROM clause (or find if already done)
        SQLTable ownerSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), ownerMapping);
        SQLExpression ownerExpr = exprFactory.newExpression(sqlStmt, ownerSqlTbl, ownerMapping);
        SQLExpression ownerVal = exprFactory.newLiteralParameter(sqlStmt, ownerMapping, null, "OWNER");
        sqlStmt.whereAnd(ownerExpr.eq(ownerVal), true);
    }
    if (relationDiscriminatorMapping != null) {
        // Apply condition on distinguisher field to filter by distinguisher (when present)
        SQLTable distSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), relationDiscriminatorMapping);
        SQLExpression distExpr = exprFactory.newExpression(sqlStmt, distSqlTbl, relationDiscriminatorMapping);
        SQLExpression distVal = exprFactory.newLiteral(sqlStmt, relationDiscriminatorMapping, relationDiscriminatorValue);
        sqlStmt.whereAnd(distExpr.eq(distVal), true);
    }
    if (orderMapping != null) {
        // Order by the ordering column, when present
        SQLTable orderSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
        SQLExpression[] orderExprs = new SQLExpression[orderMapping.getNumberOfDatastoreMappings()];
        boolean[] descendingOrder = new boolean[orderMapping.getNumberOfDatastoreMappings()];
        orderExprs[0] = exprFactory.newExpression(sqlStmt, orderSqlTbl, orderMapping);
        sqlStmt.setOrdering(orderExprs, descendingOrder);
    }
    return new IteratorStatement(this, sqlStmt, iteratorMappingClass);
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) UnionStatementGenerator(org.datanucleus.store.rdbms.sql.UnionStatementGenerator) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) DiscriminatorStatementGenerator(org.datanucleus.store.rdbms.sql.DiscriminatorStatementGenerator) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) NucleusException(org.datanucleus.exceptions.NucleusException)

Aggregations

SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)49 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)36 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)31 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)30 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)27 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)25 NucleusException (org.datanucleus.exceptions.NucleusException)25 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)24 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)19 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)19 StatementClassMapping (org.datanucleus.store.rdbms.query.StatementClassMapping)19 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)16 ExecutionContext (org.datanucleus.ExecutionContext)14 StatementMappingIndex (org.datanucleus.store.rdbms.query.StatementMappingIndex)14 UnionStatementGenerator (org.datanucleus.store.rdbms.sql.UnionStatementGenerator)12 DiscriminatorStatementGenerator (org.datanucleus.store.rdbms.sql.DiscriminatorStatementGenerator)11 PreparedStatement (java.sql.PreparedStatement)10 ResultSet (java.sql.ResultSet)10 SQLException (java.sql.SQLException)10 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)10