Search in sources :

Example 6 with UnionStatementGenerator

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

use of org.datanucleus.store.rdbms.sql.UnionStatementGenerator 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)

Example 8 with UnionStatementGenerator

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

the class JoinArrayStore 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 JOIN_TBL
 *   [JOIN ELEM_TBL ON ELEM_TBL.ID = JOIN_TBL.ELEM_ID]
 * [WHERE]
 *   [JOIN_TBL.OWNER_ID = {value}] [AND]
 *   [JOIN_TBL.DISCRIM = {discrimValue}]
 * [ORDER BY {orderClause}]
 * </pre>
 * @param ec ExecutionContext
 * @param fp FetchPlan to use in determing 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 = null;
    if (elementsAreEmbedded || elementsAreSerialised) {
        // Element = embedded, serialised (maybe Non-PC)
        // Just select the join table since we're going to return the embedded/serialised columns from it
        sqlStmt = new SelectStatement(storeMgr, containerTable, null, null);
        sqlStmt.setClassLoaderResolver(clr);
        // Select the element column - first select is assumed by SetStoreIterator
        sqlStmt.select(sqlStmt.getPrimaryTable(), elementMapping, null);
    // TODO If embedded element and it includes 1-1/N-1 in FetchPlan then select its fields also
    } else if (elementMapping instanceof ReferenceMapping) {
        // Element = Reference type (interface/Object)
        // Just select the join table since we're going to return the implementation id columns only
        sqlStmt = new SelectStatement(storeMgr, containerTable, null, null);
        sqlStmt.setClassLoaderResolver(clr);
        // Select the reference column(s) - first select is assumed by SetStoreIterator
        sqlStmt.select(sqlStmt.getPrimaryTable(), elementMapping, null);
    } else {
        // Element = PC
        // Join to the element table(s)
        iteratorMappingClass = new StatementClassMapping();
        for (int i = 0; i < elementInfo.length; i++) {
            // TODO This will only work if all element types have a discriminator
            final int elementNo = i;
            final Class elementCls = clr.classForName(elementInfo[elementNo].getClassName());
            SelectStatement elementStmt = null;
            if (elementInfo[elementNo].getDiscriminatorStrategy() != null && elementInfo[elementNo].getDiscriminatorStrategy() != DiscriminatorStrategy.NONE) {
                // The element uses a discriminator so just use that in the SELECT
                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 j = 0; j < clsNames.length; j++) {
                        cls[j] = clr.classForName(clsNames[j]);
                    }
                    SelectStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, cls, true, null, null, containerTable, null, elementMapping);
                    if (allowNulls) {
                        stmtGen.setOption(SelectStatementGenerator.OPTION_ALLOW_NULLS);
                    }
                    elementStmt = stmtGen.getStatement(ec);
                } else {
                    SelectStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, elementCls, true, null, null, containerTable, null, elementMapping);
                    if (allowNulls) {
                        stmtGen.setOption(SelectStatementGenerator.OPTION_ALLOW_NULLS);
                    }
                    elementStmt = stmtGen.getStatement(ec);
                }
                iterateUsingDiscriminator = true;
            } else {
                // No discriminator, but subclasses so use UNIONs
                SelectStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, elementCls, true, null, null, containerTable, null, elementMapping);
                stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                if (allowNulls) {
                    stmtGen.setOption(SelectStatementGenerator.OPTION_ALLOW_NULLS);
                }
                iteratorMappingClass.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
                elementStmt = stmtGen.getStatement(ec);
            }
            if (sqlStmt == null) {
                sqlStmt = elementStmt;
            } else {
                sqlStmt.union(elementStmt);
            }
        }
        if (sqlStmt == null) {
            throw new NucleusException("Error in generation of SQL statement for iterator over (Join) array. Statement is null");
        }
        // Select the required fields
        SQLTable elementSqlTbl = sqlStmt.getTable(elementInfo[0].getDatastoreClass(), sqlStmt.getPrimaryTable().getGroupName());
        SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, iteratorMappingClass, fp, elementSqlTbl, elementCmd, fp.getMaxFetchDepth());
    }
    if (addRestrictionOnOwner) {
        // Apply condition on join-table owner field to filter by owner
        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) SelectStatementGenerator(org.datanucleus.store.rdbms.sql.SelectStatementGenerator) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) 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)

Example 9 with UnionStatementGenerator

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

the class JoinSetStore 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 JOIN_TBL
 *   [JOIN ELEM_TBL ON ELEM_TBL.ID = JOIN_TBL.ELEM_ID]
 * [WHERE]
 *   [JOIN_TBL.OWNER_ID = {value}] [AND]
 *   [JOIN_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 = null;
    if (elementsAreEmbedded || elementsAreSerialised) {
        // Element = embedded, serialised (maybe Non-PC)
        // Just select the join table since we're going to return the embedded/serialised columns from it
        sqlStmt = new SelectStatement(storeMgr, containerTable, null, null);
        sqlStmt.setClassLoaderResolver(clr);
        // Select the element column - first select is assumed by SetStoreIterator
        sqlStmt.select(sqlStmt.getPrimaryTable(), elementMapping, null);
    // TODO If embedded element and it includes 1-1/N-1 in FetchPlan then select its fields also
    } else if (elementMapping instanceof ReferenceMapping) {
        // Element = Reference type (interface/Object)
        // Just select the join table since we're going to return the implementation id columns only
        sqlStmt = new SelectStatement(storeMgr, containerTable, null, null);
        sqlStmt.setClassLoaderResolver(clr);
        // Select the reference column(s) - first select is assumed by SetStoreIterator
        sqlStmt.select(sqlStmt.getPrimaryTable(), elementMapping, null);
    } else {
        // Element = PC
        // Join to the element table(s)
        iteratorMappingClass = new StatementClassMapping();
        for (int i = 0; i < elementInfo.length; i++) {
            final int elementNo = i;
            final Class elementCls = clr.classForName(elementInfo[elementNo].getClassName());
            SelectStatement elementStmt = null;
            if (elementInfo[elementNo].getDiscriminatorStrategy() != null && elementInfo[elementNo].getDiscriminatorStrategy() != DiscriminatorStrategy.NONE) {
                // The element uses a discriminator so just use that in the SELECT
                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 j = 0; j < clsNames.length; j++) {
                        cls[j] = clr.classForName(clsNames[j]);
                    }
                    SelectStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, cls, true, null, null, containerTable, null, elementMapping);
                    if (allowNulls) {
                        stmtGen.setOption(SelectStatementGenerator.OPTION_ALLOW_NULLS);
                    }
                    elementStmt = stmtGen.getStatement(ec);
                } else {
                    SelectStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, elementCls, true, null, null, containerTable, null, elementMapping);
                    if (allowNulls) {
                        stmtGen.setOption(SelectStatementGenerator.OPTION_ALLOW_NULLS);
                    }
                    elementStmt = stmtGen.getStatement(ec);
                }
                iterateUsingDiscriminator = true;
            } else {
                // No discriminator, but subclasses so use UNIONs
                SelectStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, elementCls, true, null, null, containerTable, null, elementMapping);
                stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                iteratorMappingClass.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
                elementStmt = stmtGen.getStatement(ec);
            }
            // TODO What if the first elementInfo has fields selected in one order and then the second in a different order?
            if (sqlStmt == null) {
                sqlStmt = elementStmt;
                // Select the required fields
                SQLTable elementSqlTbl = sqlStmt.getTable(elementInfo[i].getDatastoreClass(), sqlStmt.getPrimaryTable().getGroupName());
                SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, iteratorMappingClass, fp, elementSqlTbl, elementCmd, fp.getMaxFetchDepth());
            } else {
                // Select the required fields
                SQLTable elementSqlTbl = elementStmt.getTable(elementInfo[i].getDatastoreClass(), elementStmt.getPrimaryTable().getGroupName());
                SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(elementStmt, iteratorMappingClass, fp, elementSqlTbl, elementCmd, fp.getMaxFetchDepth());
                sqlStmt.union(elementStmt);
            }
        }
    }
    if (sqlStmt == null) {
        throw new NucleusException("Error in generation of SQL statement for iterator over (Join) set. Statement is null");
    }
    if (addRestrictionOnOwner) {
        // Apply condition on join-table owner field to filter by owner
        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) {
        // TODO If we have multiple roots then cannot allow this
        // 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) SelectStatementGenerator(org.datanucleus.store.rdbms.sql.SelectStatementGenerator) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) 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)

Example 10 with UnionStatementGenerator

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

the class MapKeySetStore method getSQLStatementForIterator.

/**
 * Method to generate an SQLStatement for iterating through keys of the map.
 * Populates the iteratorMappingDef and iteratorMappingParams.
 * Creates a statement that selects the key table(s), and adds any necessary join to the containerTable
 * if that is not the key table. If the key is embedded then selects the table it is embedded in.
 * Adds a restriction on the ownerMapping of the containerTable so we can restrict to the owner object.
 * @param ownerOP ObjectProvider for the owner object
 * @return The SQLStatement
 */
protected SelectStatement getSQLStatementForIterator(ObjectProvider ownerOP) {
    SelectStatement sqlStmt = null;
    ExecutionContext ec = ownerOP.getExecutionContext();
    final ClassLoaderResolver clr = ec.getClassLoaderResolver();
    final Class keyCls = clr.classForName(elementType);
    SQLTable containerSqlTbl = null;
    MapType mapType = getOwnerMemberMetaData().getMap().getMapType();
    FetchPlan fp = ec.getFetchPlan();
    if (elementCmd != null && elementCmd.getDiscriminatorStrategyForTable() != null && elementCmd.getDiscriminatorStrategyForTable() != DiscriminatorStrategy.NONE) {
        // Map<PC, ?> where key has discriminator
        if (ClassUtils.isReferenceType(keyCls)) {
            // Take the metadata for the first implementation of the reference type
            String[] clsNames = storeMgr.getNucleusContext().getMetaDataManager().getClassesImplementingInterface(elementType, clr);
            Class[] cls = new Class[clsNames.length];
            for (int j = 0; j < clsNames.length; j++) {
                cls[j] = clr.classForName(clsNames[j]);
            }
            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);
        }
        containerSqlTbl = sqlStmt.getPrimaryTable();
        iterateUsingDiscriminator = true;
        if (mapType == MapType.MAP_TYPE_VALUE_IN_KEY) {
            // Select key fields
            containerSqlTbl = sqlStmt.getPrimaryTable();
            iteratorMappingDef = new StatementClassMapping();
            SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, iteratorMappingDef, fp, sqlStmt.getPrimaryTable(), elementCmd, fp.getMaxFetchDepth());
        } else {
            // MAP_TYPE_KEY_IN_VALUE, MAP_TYPE_JOIN
            // Join to join table and select key fields
            JavaTypeMapping keyIdMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
            containerSqlTbl = sqlStmt.join(JoinType.INNER_JOIN, sqlStmt.getPrimaryTable(), keyIdMapping, containerTable, null, elementMapping, null, null, true);
            iteratorMappingDef = new StatementClassMapping();
            SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, iteratorMappingDef, fp, sqlStmt.getPrimaryTable(), elementCmd, fp.getMaxFetchDepth());
        }
    } else {
        if (mapType == MapType.MAP_TYPE_VALUE_IN_KEY) {
            // Select of key in key table (allow union of possible key types)
            iteratorMappingDef = new StatementClassMapping();
            UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, keyCls, true, null, null);
            stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
            iteratorMappingDef.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
            sqlStmt = stmtGen.getStatement(ec);
            containerSqlTbl = sqlStmt.getPrimaryTable();
            SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, iteratorMappingDef, fp, sqlStmt.getPrimaryTable(), elementCmd, fp.getMaxFetchDepth());
        } else {
            // MAP_TYPE_KEY_IN_VALUE, MAP_TYPE_JOIN
            if (elementCmd != null) {
                // Select of key table, joining to join table
                iteratorMappingDef = new StatementClassMapping();
                UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, keyCls, true, null, null);
                stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                iteratorMappingDef.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
                sqlStmt = stmtGen.getStatement(ec);
                JavaTypeMapping keyIdMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
                containerSqlTbl = sqlStmt.join(JoinType.INNER_JOIN, sqlStmt.getPrimaryTable(), keyIdMapping, containerTable, null, elementMapping, null, null, true);
                SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, iteratorMappingDef, fp, sqlStmt.getPrimaryTable(), elementCmd, fp.getMaxFetchDepth());
            } else {
                // Select of key in join table
                sqlStmt = new SelectStatement(storeMgr, containerTable, null, null);
                sqlStmt.setClassLoaderResolver(clr);
                containerSqlTbl = sqlStmt.getPrimaryTable();
                SQLTable elemSqlTblForKey = containerSqlTbl;
                if (elementMapping.getTable() != containerSqlTbl.getTable()) {
                    elemSqlTblForKey = sqlStmt.getTableForDatastoreContainer(elementMapping.getTable());
                    if (elemSqlTblForKey == null) {
                        // Add join to element table
                        elemSqlTblForKey = sqlStmt.join(JoinType.INNER_JOIN, sqlStmt.getPrimaryTable(), sqlStmt.getPrimaryTable().getTable().getIdMapping(), elementMapping.getTable(), null, elementMapping.getTable().getIdMapping(), null, null, true);
                    }
                }
                sqlStmt.select(elemSqlTblForKey, elementMapping, null);
            }
        }
    }
    // Apply condition on owner field to filter by owner
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    SQLTable ownerSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, containerSqlTbl, ownerMapping);
    SQLExpression ownerExpr = exprFactory.newExpression(sqlStmt, ownerSqlTbl, ownerMapping);
    SQLExpression ownerVal = exprFactory.newLiteralParameter(sqlStmt, ownerMapping, null, "OWNER");
    sqlStmt.whereAnd(ownerExpr.eq(ownerVal), true);
    // Input parameter(s) - the owner
    int inputParamNum = 1;
    StatementMappingIndex ownerIdx = new StatementMappingIndex(ownerMapping);
    if (sqlStmt.getNumberOfUnions() > 0) {
        // Add parameter occurrence for each union of statement
        for (int j = 0; j < sqlStmt.getNumberOfUnions() + 1; j++) {
            int[] paramPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
            for (int k = 0; k < ownerMapping.getNumberOfDatastoreMappings(); k++) {
                paramPositions[k] = inputParamNum++;
            }
            ownerIdx.addParameterOccurrence(paramPositions);
        }
    } else {
        int[] paramPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
        for (int k = 0; k < ownerMapping.getNumberOfDatastoreMappings(); k++) {
            paramPositions[k] = inputParamNum++;
        }
        ownerIdx.addParameterOccurrence(paramPositions);
    }
    iteratorMappingParams = new StatementParameterMapping();
    iteratorMappingParams.addMappingForParameter("owner", ownerIdx);
    return sqlStmt;
}
Also used : StatementParameterMapping(org.datanucleus.store.rdbms.query.StatementParameterMapping) 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) FetchPlan(org.datanucleus.FetchPlan) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) MapType(org.datanucleus.metadata.MapMetaData.MapType) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) UnionStatementGenerator(org.datanucleus.store.rdbms.sql.UnionStatementGenerator) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) ExecutionContext(org.datanucleus.ExecutionContext) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) DiscriminatorStatementGenerator(org.datanucleus.store.rdbms.sql.DiscriminatorStatementGenerator) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass)

Aggregations

SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)12 UnionStatementGenerator (org.datanucleus.store.rdbms.sql.UnionStatementGenerator)12 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)11 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)11 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)11 StatementClassMapping (org.datanucleus.store.rdbms.query.StatementClassMapping)10 DiscriminatorStatementGenerator (org.datanucleus.store.rdbms.sql.DiscriminatorStatementGenerator)10 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)10 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)6 NucleusException (org.datanucleus.exceptions.NucleusException)6 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)6 SelectStatementGenerator (org.datanucleus.store.rdbms.sql.SelectStatementGenerator)5 ExecutionContext (org.datanucleus.ExecutionContext)4 StatementMappingIndex (org.datanucleus.store.rdbms.query.StatementMappingIndex)4 StatementParameterMapping (org.datanucleus.store.rdbms.query.StatementParameterMapping)4 ReferenceMapping (org.datanucleus.store.rdbms.mapping.java.ReferenceMapping)3 FetchPlan (org.datanucleus.FetchPlan)2 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)2 MapType (org.datanucleus.metadata.MapMetaData.MapType)2 FieldOrder (org.datanucleus.metadata.OrderMetaData.FieldOrder)2