Search in sources :

Example 61 with StatementMappingIndex

use of org.datanucleus.store.rdbms.query.StatementMappingIndex in project datanucleus-rdbms by datanucleus.

the class MapEntrySetStore method iterator.

/**
 * Method returning an iterator across the entries in the map for this owner object.
 * @param ownerSM StateManager of the owning object
 * @return The iterator for the entries (<pre>map.entrySet().iterator()</pre>).
 */
public Iterator<Map.Entry<K, V>> iterator(DNStateManager ownerSM) {
    ExecutionContext ec = ownerSM.getExecutionContext();
    Boolean serializeRead = ec.getTransaction().getSerializeRead();
    String stmtSql = serializeRead ? iteratorSelectStmtLockedSql : iteratorSelectStmtSql;
    if (stmtSql == null) {
        synchronized (// Make sure this completes in case another thread needs the same info
        this) {
            // Generate the statement
            SelectStatement selectStmt = getSQLStatementForIterator(ownerSM, ec.getFetchPlan(), true);
            // Input parameter(s) - the owner
            int inputParamNum = 1;
            StatementMappingIndex ownerIdx = new StatementMappingIndex(ownerMapping);
            if (selectStmt.getNumberOfUnions() > 0) {
                // Add parameter occurrence for each union of statement
                for (int j = 0; j < selectStmt.getNumberOfUnions() + 1; j++) {
                    int[] paramPositions = new int[ownerMapping.getNumberOfColumnMappings()];
                    for (int k = 0; k < ownerMapping.getNumberOfColumnMappings(); k++) {
                        paramPositions[k] = inputParamNum++;
                    }
                    ownerIdx.addParameterOccurrence(paramPositions);
                }
            } else {
                int[] paramPositions = new int[ownerMapping.getNumberOfColumnMappings()];
                for (int k = 0; k < ownerMapping.getNumberOfColumnMappings(); k++) {
                    paramPositions[k] = inputParamNum++;
                }
                ownerIdx.addParameterOccurrence(paramPositions);
            }
            iteratorMappingParams = new StatementParameterMapping();
            iteratorMappingParams.addMappingForParameter("owner", ownerIdx);
            // Save the two possible select statements (normal, locked)
            iteratorSelectStmtSql = selectStmt.getSQLText().toSQL();
            selectStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
            iteratorSelectStmtLockedSql = selectStmt.getSQLText().toSQL();
        }
        stmtSql = serializeRead ? iteratorSelectStmtLockedSql : iteratorSelectStmtSql;
    }
    try {
        ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
        SQLController sqlControl = storeMgr.getSQLController();
        try {
            // Create the statement and set the owner
            PreparedStatement ps = sqlControl.getStatementForQuery(mconn, stmtSql);
            StatementMappingIndex ownerIdx = iteratorMappingParams.getMappingForParameter("owner");
            int numParams = ownerIdx.getNumberOfParameterOccurrences();
            for (int paramInstance = 0; paramInstance < numParams; paramInstance++) {
                ownerIdx.getMapping().setObject(ec, ps, ownerIdx.getParameterPositionsForOccurrence(paramInstance), ownerSM.getObject());
            }
            try {
                ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, stmtSql, ps);
                try {
                    return new SetIterator(ownerSM, this, ownerMemberMetaData, rs, iteratorKeyResultCols, iteratorValueResultCols) {

                        protected boolean next(Object rs) {
                            try {
                                return ((ResultSet) rs).next();
                            } catch (SQLException e) {
                                throw new NucleusDataStoreException("SQLException", e);
                            }
                        }
                    };
                } finally {
                    rs.close();
                }
            } finally {
                sqlControl.closeStatement(mconn, ps);
            }
        } finally {
            mconn.release();
        }
    } catch (SQLException e) {
        throw new NucleusDataStoreException(Localiser.msg("056012", stmtSql), e);
    }
}
Also used : StatementParameterMapping(org.datanucleus.store.rdbms.query.StatementParameterMapping) SQLException(java.sql.SQLException) PreparedStatement(java.sql.PreparedStatement) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) SQLController(org.datanucleus.store.rdbms.SQLController) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) ExecutionContext(org.datanucleus.ExecutionContext) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection)

Example 62 with StatementMappingIndex

use of org.datanucleus.store.rdbms.query.StatementMappingIndex in project datanucleus-rdbms by datanucleus.

the class MapValueCollectionStore method getSQLStatementForIterator.

/**
 * Method to generate an SQLStatement for iterating through values of the map.
 * Populates the iteratorMappingDef and iteratorMappingParams.
 * Creates a statement that selects the value table(s), and adds any necessary join to the containerTable
 * if that is not the value table. If the value 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 ownerSM StateManager for the owner object
 * @return The SQLStatement
 */
protected SelectStatement getSQLStatementForIterator(DNStateManager ownerSM) {
    SelectStatement sqlStmt = null;
    ExecutionContext ec = ownerSM.getExecutionContext();
    final ClassLoaderResolver clr = ec.getClassLoaderResolver();
    final Class valueCls = 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 value has discriminator
        if (ClassUtils.isReferenceType(valueCls)) {
            // 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]);
            }
            SelectStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, cls, true, null, null);
            sqlStmt = stmtGen.getStatement(ec);
        } else {
            SelectStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, valueCls, true, null, null);
            sqlStmt = stmtGen.getStatement(ec);
        }
        iterateUsingDiscriminator = true;
        if (mapType == MapType.MAP_TYPE_VALUE_IN_KEY) {
            // Join to key table and select value fields
            JavaTypeMapping valueIdMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
            containerSqlTbl = sqlStmt.join(JoinType.INNER_JOIN, sqlStmt.getPrimaryTable(), valueIdMapping, 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_KEY_IN_VALUE) {
            // Select value fields
            containerSqlTbl = sqlStmt.getPrimaryTable();
            iteratorMappingDef = new StatementClassMapping();
            SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, iteratorMappingDef, fp, sqlStmt.getPrimaryTable(), elementCmd, fp.getMaxFetchDepth());
        } else {
            // Join to join table and select value fields
            JavaTypeMapping valueIdMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
            containerSqlTbl = sqlStmt.join(JoinType.INNER_JOIN, sqlStmt.getPrimaryTable(), valueIdMapping, 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) {
            if (elementCmd != null) {
                // TODO Allow for null value [change to select the key table and left outer join to the key]
                // Select of value table, joining to key table
                iteratorMappingDef = new StatementClassMapping();
                UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, valueCls, true, null, null);
                stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                iteratorMappingDef.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
                sqlStmt = stmtGen.getStatement(ec);
                JavaTypeMapping valueIdMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
                containerSqlTbl = sqlStmt.join(JoinType.INNER_JOIN, sqlStmt.getPrimaryTable(), valueIdMapping, containerTable, null, elementMapping, null, null, true);
                SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, iteratorMappingDef, fp, sqlStmt.getPrimaryTable(), elementCmd, fp.getMaxFetchDepth());
            } else {
                // Select of value in key table
                sqlStmt = new SelectStatement(storeMgr, containerTable, null, null);
                sqlStmt.setClassLoaderResolver(clr);
                containerSqlTbl = sqlStmt.getPrimaryTable();
                SQLTable elemSqlTblForValue = containerSqlTbl;
                if (elementMapping.getTable() != containerSqlTbl.getTable()) {
                    elemSqlTblForValue = sqlStmt.getTableForDatastoreContainer(elementMapping.getTable());
                    if (elemSqlTblForValue == null) {
                        // Add join to key table holding value
                        elemSqlTblForValue = sqlStmt.join(JoinType.INNER_JOIN, sqlStmt.getPrimaryTable(), sqlStmt.getPrimaryTable().getTable().getIdMapping(), elementMapping.getTable(), null, elementMapping.getTable().getIdMapping(), null, null, true);
                    }
                }
                sqlStmt.select(elemSqlTblForValue, elementMapping, null);
            }
        } else if (mapType == MapType.MAP_TYPE_KEY_IN_VALUE) {
            // Select of value in value table (allow union of possible value types)
            iteratorMappingDef = new StatementClassMapping();
            UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, valueCls, 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 {
            if (elementCmd != null) {
                // TODO Allow for null value [change to select the join table and left outer join to the key]
                // Select of value table, joining to key table
                iteratorMappingDef = new StatementClassMapping();
                UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, valueCls, true, null, null);
                stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                iteratorMappingDef.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
                sqlStmt = stmtGen.getStatement(ec);
                JavaTypeMapping valueIdMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
                containerSqlTbl = sqlStmt.join(JoinType.INNER_JOIN, sqlStmt.getPrimaryTable(), valueIdMapping, containerTable, null, elementMapping, null, null, true);
                SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, iteratorMappingDef, fp, sqlStmt.getPrimaryTable(), elementCmd, fp.getMaxFetchDepth());
            } else {
                // Select of value in join table
                sqlStmt = new SelectStatement(storeMgr, containerTable, null, null);
                containerSqlTbl = sqlStmt.getPrimaryTable();
                sqlStmt.select(sqlStmt.getPrimaryTable(), 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.getNumberOfColumnMappings()];
            for (int k = 0; k < ownerMapping.getNumberOfColumnMappings(); k++) {
                paramPositions[k] = inputParamNum++;
            }
            ownerIdx.addParameterOccurrence(paramPositions);
        }
    } else {
        int[] paramPositions = new int[ownerMapping.getNumberOfColumnMappings()];
        for (int k = 0; k < ownerMapping.getNumberOfColumnMappings(); 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) SelectStatementGenerator(org.datanucleus.store.rdbms.sql.SelectStatementGenerator) 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)

Example 63 with StatementMappingIndex

use of org.datanucleus.store.rdbms.query.StatementMappingIndex in project datanucleus-rdbms by datanucleus.

the class SQLStatementHelper method selectIdentityOfCandidateInStatement.

/**
 * Method to select the identity for the candidate class.
 * The supplied statement and mapping definition are updated during this method.
 * Selects the datastore id (if using datastore id) as "DN_DATASTOREID",
 * the version (if present) as "DN_VERSION", the discriminator (if present) as "DN_DISCRIM",
 * and the application id (if using application id) as "DN_APPID_{i}"
 * @param stmt The statement
 * @param mappingDefinition Mapping definition for result columns
 * @param candidateCmd The candidate class meta-data
 */
public static void selectIdentityOfCandidateInStatement(SelectStatement stmt, StatementClassMapping mappingDefinition, AbstractClassMetaData candidateCmd) {
    DatastoreClass candidateTbl = (DatastoreClass) stmt.getPrimaryTable().getTable();
    if (candidateCmd.getIdentityType() == IdentityType.DATASTORE) {
        // Datastore-identity surrogate column
        JavaTypeMapping idMapping = candidateTbl.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false);
        int[] colNumbers = stmt.select(stmt.getPrimaryTable(), idMapping, "DN_DATASTOREID", false);
        if (mappingDefinition != null) {
            StatementMappingIndex datastoreIdIdx = new StatementMappingIndex(idMapping);
            datastoreIdIdx.setColumnPositions(colNumbers);
            mappingDefinition.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), datastoreIdIdx);
        }
    } else if (candidateCmd.getIdentityType() == IdentityType.APPLICATION) {
        // Application-identity column(s)
        int[] pkPositions = candidateCmd.getPKMemberPositions();
        String alias = "DN_APPID";
        for (int i = 0; i < pkPositions.length; i++) {
            AbstractMemberMetaData pkMmd = candidateCmd.getMetaDataForManagedMemberAtAbsolutePosition(pkPositions[i]);
            JavaTypeMapping pkMapping = candidateTbl.getMemberMapping(pkMmd);
            SQLTable sqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, stmt.getPrimaryTable(), pkMapping);
            if (pkPositions.length > 1) {
                alias = "DN_APPID" + i;
            }
            int[] colNumbers = stmt.select(sqlTbl, pkMapping, alias, false);
            if (mappingDefinition != null) {
                StatementMappingIndex appIdIdx = new StatementMappingIndex(pkMapping);
                appIdIdx.setColumnPositions(colNumbers);
                mappingDefinition.addMappingForMember(pkPositions[i], appIdIdx);
            }
        }
    }
    JavaTypeMapping verMapping = candidateTbl.getSurrogateMapping(SurrogateColumnType.VERSION, true);
    if (verMapping != null) {
        // Version surrogate column (adds inner join to any required superclass table)
        SQLTable versionSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, stmt.getPrimaryTable(), verMapping);
        int[] colNumbers = stmt.select(versionSqlTbl, verMapping, "DN_VERSION", false);
        if (mappingDefinition != null) {
            StatementMappingIndex versionIdx = new StatementMappingIndex(verMapping);
            versionIdx.setColumnPositions(colNumbers);
            mappingDefinition.addMappingForMember(SurrogateColumnType.VERSION.getFieldNumber(), versionIdx);
        }
    }
    JavaTypeMapping discrimMapping = candidateTbl.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
    if (discrimMapping != null) {
        // Discriminator surrogate column (adds inner join to any required superclass table)
        SQLTable discrimSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, stmt.getPrimaryTable(), discrimMapping);
        int[] colNumbers = stmt.select(discrimSqlTbl, discrimMapping, "DN_DISCRIM", false);
        if (mappingDefinition != null) {
            StatementMappingIndex discrimIdx = new StatementMappingIndex(discrimMapping);
            discrimIdx.setColumnPositions(colNumbers);
            mappingDefinition.addMappingForMember(SurrogateColumnType.DISCRIMINATOR.getFieldNumber(), discrimIdx);
        }
    }
    List<SelectStatement> unionStmts = stmt.getUnions();
    if (unionStmts != null) {
        Iterator<SelectStatement> iter = unionStmts.iterator();
        while (iter.hasNext()) {
            SelectStatement unionStmt = iter.next();
            selectIdentityOfCandidateInStatement(unionStmt, null, candidateCmd);
        }
    }
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 64 with StatementMappingIndex

use of org.datanucleus.store.rdbms.query.StatementMappingIndex in project datanucleus-rdbms by datanucleus.

the class SQLStatementHelper method selectFetchPlanOfSourceClassInStatement.

/**
 * Method to select all fetch plan members for the "source" class.
 * If the passed FetchPlan is null then the default fetch group fields will be selected.
 * The source class is defined by the supplied meta-data, and the SQLTable that we are selecting from.
 * The supplied statement and mapping definition are updated during this method.
 * @param stmt The statement
 * @param mappingDefinition Mapping definition for result columns (populated with column positions
 *                          of any selected mappings if provided as input)
 * @param fetchPlan FetchPlan in use
 * @param sourceSqlTbl SQLTable for the source class that we select from
 * @param sourceCmd Meta-data for the source class
 * @param maxFetchDepth Max fetch depth from this point to select (0 implies no other objects)
 * @param inputJoinType Optional join type to use for subobjects (otherwise decide join type internally)
 */
public static void selectFetchPlanOfSourceClassInStatement(SelectStatement stmt, StatementClassMapping mappingDefinition, FetchPlan fetchPlan, SQLTable sourceSqlTbl, AbstractClassMetaData sourceCmd, int maxFetchDepth, JoinType inputJoinType) {
    DatastoreClass sourceTbl = (DatastoreClass) sourceSqlTbl.getTable();
    int[] fieldNumbers;
    if (fetchPlan != null) {
        // Use FetchPlan fields
        fieldNumbers = fetchPlan.getFetchPlanForClass(sourceCmd).getMemberNumbers();
    } else {
        // Use DFG fields
        fieldNumbers = sourceCmd.getDFGMemberPositions();
    }
    ClassLoaderResolver clr = stmt.getRDBMSManager().getNucleusContext().getClassLoaderResolver(null);
    for (int fieldNumber : fieldNumbers) {
        AbstractMemberMetaData mmd = sourceCmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
        selectMemberOfSourceInStatement(stmt, mappingDefinition, fetchPlan, sourceSqlTbl, mmd, clr, maxFetchDepth, inputJoinType);
    }
    if (sourceCmd.getIdentityType() == IdentityType.DATASTORE) {
        // Datastore-identity surrogate column
        JavaTypeMapping idMapping = sourceTbl.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false);
        int[] colNumbers = stmt.select(sourceSqlTbl, idMapping, null);
        if (mappingDefinition != null) {
            StatementMappingIndex datastoreIdIdx = new StatementMappingIndex(idMapping);
            datastoreIdIdx.setColumnPositions(colNumbers);
            mappingDefinition.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), datastoreIdIdx);
        }
    }
    JavaTypeMapping verMapping = sourceTbl.getSurrogateMapping(SurrogateColumnType.VERSION, true);
    if (verMapping != null) {
        // Version surrogate column (adds inner join to any required superclass table)
        SQLTable versionSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, sourceSqlTbl, verMapping);
        int[] colNumbers = stmt.select(versionSqlTbl, verMapping, null);
        if (mappingDefinition != null) {
            StatementMappingIndex versionIdx = new StatementMappingIndex(verMapping);
            versionIdx.setColumnPositions(colNumbers);
            mappingDefinition.addMappingForMember(SurrogateColumnType.VERSION.getFieldNumber(), versionIdx);
        }
    }
    JavaTypeMapping discrimMapping = sourceTbl.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
    if (discrimMapping != null) {
        // Discriminator surrogate column (adds inner join to any required superclass table)
        SQLTable discrimSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, sourceSqlTbl, discrimMapping);
        int[] colNumbers = stmt.select(discrimSqlTbl, discrimMapping, null);
        if (mappingDefinition != null) {
            StatementMappingIndex discrimIdx = new StatementMappingIndex(discrimMapping);
            discrimIdx.setColumnPositions(colNumbers);
            mappingDefinition.addMappingForMember(SurrogateColumnType.DISCRIMINATOR.getFieldNumber(), discrimIdx);
        }
    }
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 65 with StatementMappingIndex

use of org.datanucleus.store.rdbms.query.StatementMappingIndex in project datanucleus-rdbms by datanucleus.

the class SQLStatementHelper method selectMemberOfSourceInStatement.

/**
 * Method to select the specified member (field/property) of the source table in the passed SQL
 * statement. This populates the mappingDefinition with the column details for this member.
 * @param stmt The SQL statement
 * @param mappingDefinition Mapping definition for the results (will be populated by any
 *                          selected mappings if provided as input)
 * @param fetchPlan FetchPlan
 * @param sourceSqlTbl Table that has the member (or a super-table/secondary-table of this table)
 * @param mmd Meta-data for the field/property in the source that we are selecting
 * @param clr ClassLoader resolver
 * @param maxFetchPlanLimit Max fetch depth from this point to select (0 implies no other objects)
 * @param inputJoinType Optional join type to use for subobjects (otherwise decide join type internally)
 */
public static void selectMemberOfSourceInStatement(SelectStatement stmt, StatementClassMapping mappingDefinition, FetchPlan fetchPlan, SQLTable sourceSqlTbl, AbstractMemberMetaData mmd, ClassLoaderResolver clr, int maxFetchPlanLimit, JoinType inputJoinType) {
    boolean selectSubobjects = false;
    if (maxFetchPlanLimit > 0) {
        selectSubobjects = true;
    }
    if (mmd.fetchFKOnly()) {
        // Equivalent to recursion-depth=0
        selectSubobjects = false;
    }
    if (fetchPlan != null) {
        FetchPlanForClass fpClass = fetchPlan.getFetchPlanForClass(mmd.getAbstractClassMetaData());
        if (RelationType.isRelationSingleValued(mmd.getRelationType(clr)) && fpClass.getRecursionDepthForMember(mmd.getAbsoluteFieldNumber()) == 0) {
            // User has marked this member as recursion-depth=0 meaning pull in just the FK and dont join to the sub-object
            selectSubobjects = false;
        }
    }
    // Set table-group name for any related object we join to (naming based on member name)
    String tableGroupName = sourceSqlTbl.getGroupName() + "." + mmd.getName();
    JavaTypeMapping m = sourceSqlTbl.getTable().getMemberMapping(mmd);
    if (m != null && m.includeInFetchStatement()) {
        RelationType relationType = mmd.getRelationType(clr);
        RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
        DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
        if (!dba.validToSelectMappingInStatement(stmt, m)) {
            // Not valid to select this mapping for this statement so return
            return;
        }
        MetaDataManager mmgr = storeMgr.getMetaDataManager();
        StatementMappingIndex stmtMapping = new StatementMappingIndex(m);
        if (m.getNumberOfColumnMappings() > 0) {
            // Select of fields with columns in source table(s)
            // Adds inner/outer join to any required superclass/secondary tables
            SQLTable sqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, sourceSqlTbl, m);
            boolean selectFK = true;
            if (selectSubobjects && (relationType == RelationType.ONE_TO_ONE_UNI || (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() == null)) && !mmd.isSerialized() && !mmd.isEmbedded()) {
                // Related object with FK at this side
                selectFK = selectFetchPlanFieldsOfFKRelatedObject(stmt, mappingDefinition, fetchPlan, sourceSqlTbl, mmd, clr, maxFetchPlanLimit, m, tableGroupName, stmtMapping, sqlTbl, inputJoinType);
            } else if (selectSubobjects && (!mmd.isEmbedded() && !mmd.isSerialized()) && relationType == RelationType.MANY_TO_ONE_BI) {
                AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                if (mmd.getJoinMetaData() != null || relatedMmds[0].getJoinMetaData() != null) {
                    // N-1 bidirectional join table relation
                    // TODO Add left outer join from {sourceTable}.ID to {joinTable}.ELEM_FK
                    Table joinTable = storeMgr.getTable(relatedMmds[0]);
                    ElementContainerTable collTable = (ElementContainerTable) joinTable;
                    JavaTypeMapping selectMapping = collTable.getOwnerMapping();
                    SQLTable joinSqlTbl = null;
                    if (stmt.getPrimaryTable().getTable() != joinTable) {
                        // Join to the join table
                        JavaTypeMapping referenceMapping = collTable.getElementMapping();
                        joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), collTable, null, referenceMapping, null, tableGroupName, true);
                    } else {
                        // Main table of the statement is the join table so no need to join
                        joinSqlTbl = stmt.getPrimaryTable();
                    }
                    // Select the owner mapping of the join table
                    int[] colNumbers = stmt.select(joinSqlTbl, selectMapping, null);
                    stmtMapping.setColumnPositions(colNumbers);
                // TODO Join to 1 side from join table?
                } else {
                    // N-1 bidirectional FK relation
                    // Related object with FK at this side, so join/select related object as required
                    selectFK = selectFetchPlanFieldsOfFKRelatedObject(stmt, mappingDefinition, fetchPlan, sourceSqlTbl, mmd, clr, maxFetchPlanLimit, m, tableGroupName, stmtMapping, sqlTbl, inputJoinType);
                }
            }
            if (selectFK) {
                int[] colNumbers = stmt.select(sqlTbl, m, null);
                stmtMapping.setColumnPositions(colNumbers);
            }
        } else {
            // Select of related objects with FK in other table
            if (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() != null) {
                // 1-1 bidirectional relation with FK in related table
                AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                AbstractMemberMetaData relatedMmd = relatedMmds[0];
                String[] clsNames = null;
                if (mmd.getType().isInterface()) {
                    if (mmd.getFieldTypes() != null && mmd.getFieldTypes().length == 1) {
                        // Use field-type since only one class specified
                        Class fldTypeCls = clr.classForName(mmd.getFieldTypes()[0]);
                        if (fldTypeCls.isInterface()) {
                            // User has specified an interface, so find its implementations
                            clsNames = mmgr.getClassesImplementingInterface(mmd.getFieldTypes()[0], clr);
                        } else {
                            // Use user-provided field-type
                            clsNames = new String[] { mmd.getFieldTypes()[0] };
                        }
                    }
                    if (clsNames == null) {
                        clsNames = mmgr.getClassesImplementingInterface(mmd.getTypeName(), clr);
                    }
                } else {
                    String typeName = mmd.isSingleCollection() ? mmd.getCollection().getElementType() : mmd.getTypeName();
                    clsNames = new String[] { typeName };
                }
                DatastoreClass relatedTbl = storeMgr.getDatastoreClass(clsNames[0], clr);
                JavaTypeMapping relatedMapping = relatedTbl.getMemberMapping(relatedMmd);
                JavaTypeMapping relatedDiscrimMapping = relatedTbl.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
                Object[] discrimValues = null;
                JavaTypeMapping relatedTypeMapping = null;
                AbstractClassMetaData relatedCmd = relatedMmd.getAbstractClassMetaData();
                if (relatedDiscrimMapping != null && (relatedCmd.getSuperAbstractClassMetaData() != null || !relatedCmd.getFullClassName().equals(mmd.getTypeName()))) {
                    // Related table has a discriminator and the field can store other types
                    List discValueList = null;
                    for (String clsName : clsNames) {
                        List values = getDiscriminatorValuesForMember(clsName, relatedDiscrimMapping, storeMgr, clr);
                        if (discValueList == null) {
                            discValueList = values;
                        } else {
                            discValueList.addAll(values);
                        }
                    }
                    if (discValueList != null) {
                        discrimValues = discValueList.toArray(new Object[discValueList.size()]);
                    }
                } else if (relatedTbl != relatedMapping.getTable()) {
                    // The relation is to a base class table, and the type stored is a sub-class
                    relatedTypeMapping = relatedTbl.getIdMapping();
                }
                SQLTable relatedSqlTbl = null;
                if (relatedTypeMapping == null) {
                    // Join the 1-1 relation, if not already joined
                    relatedSqlTbl = stmt.getTable(relatedTbl, tableGroupName);
                    if (relatedSqlTbl == null) {
                        JoinType joinType = getJoinTypeForOneToOneRelationJoin(sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, inputJoinType);
                        if (joinType == JoinType.LEFT_OUTER_JOIN || joinType == JoinType.RIGHT_OUTER_JOIN) {
                            inputJoinType = joinType;
                        }
                        relatedSqlTbl = addJoinForOneToOneRelation(stmt, sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, relatedMapping, relatedTbl, null, discrimValues, tableGroupName, joinType);
                    }
                    // Select the id mapping in the related table
                    int[] colNumbers = stmt.select(relatedSqlTbl, relatedTbl.getIdMapping(), null);
                    stmtMapping.setColumnPositions(colNumbers);
                } else {
                    DatastoreClass relationTbl = (DatastoreClass) relatedMapping.getTable();
                    if (relatedTbl != relatedMapping.getTable()) {
                        if (relatedMapping.isNullable()) {
                            // Nullable - left outer join from {sourceTable}.ID to {relatedBaseTable}.FK
                            // and inner join from {relatedBaseTable}.ID to {relatedTable}.ID
                            // (joins the relation and restricts to the right type)
                            relatedSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), relatedMapping.getTable(), null, relatedMapping, null, tableGroupName, true);
                            relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, relatedSqlTbl, relatedMapping.getTable().getIdMapping(), relatedTbl, null, relatedTbl.getIdMapping(), null, tableGroupName, true);
                        } else {
                            // Not nullable - inner join from {sourceTable}.ID to {relatedBaseTable}.FK
                            // and inner join from {relatedBaseTable}.ID to {relatedTable}.ID
                            // (joins the relation and restricts to the right type)
                            relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), relatedMapping.getTable(), null, relatedMapping, null, tableGroupName, true);
                            relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, relatedSqlTbl, relatedMapping.getTable().getIdMapping(), relatedTbl, null, relatedTbl.getIdMapping(), null, tableGroupName, true);
                        }
                    } else {
                        // Join the 1-1 relation, if not already joined
                        relatedSqlTbl = stmt.getTable(relatedTbl, tableGroupName);
                        if (relatedSqlTbl == null) {
                            JoinType joinType = getJoinTypeForOneToOneRelationJoin(sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, inputJoinType);
                            if (joinType == JoinType.LEFT_OUTER_JOIN || joinType == JoinType.RIGHT_OUTER_JOIN) {
                                inputJoinType = joinType;
                            }
                            relatedSqlTbl = addJoinForOneToOneRelation(stmt, sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, relatedMapping, relationTbl, null, null, tableGroupName, joinType);
                        }
                    }
                    // Select the id mapping in the subclass of the related table
                    // Note this adds an inner join from relatedTable to its subclass
                    relatedSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, relatedSqlTbl, relatedTbl.getIdMapping());
                    int[] colNumbers = stmt.select(relatedSqlTbl, relatedTbl.getIdMapping(), null);
                    stmtMapping.setColumnPositions(colNumbers);
                }
                if (selectSubobjects && !mmd.isSerialized() && !mmd.isEmbedded()) {
                    // Select the fetch-plan fields of the related object
                    StatementClassMapping subMappingDefinition = new StatementClassMapping(null, mmd.getName());
                    selectFetchPlanOfSourceClassInStatement(stmt, subMappingDefinition, fetchPlan, relatedSqlTbl, relatedMmd.getAbstractClassMetaData(), maxFetchPlanLimit - 1, inputJoinType);
                    if (mappingDefinition != null) {
                        mappingDefinition.addMappingDefinitionForMember(mmd.getAbsoluteFieldNumber(), subMappingDefinition);
                    }
                }
            } else if (relationType == RelationType.MANY_TO_ONE_BI) {
                AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                if (mmd.getJoinMetaData() != null || relatedMmds[0].getJoinMetaData() != null) {
                    // N-1 bidirectional join table relation
                    // Add left outer join from {sourceTable}.ID to {joinTable}.ELEM_FK
                    Table joinTable = storeMgr.getTable(relatedMmds[0]);
                    ElementContainerTable collTable = (ElementContainerTable) joinTable;
                    JavaTypeMapping selectMapping = collTable.getOwnerMapping();
                    SQLTable joinSqlTbl = null;
                    if (stmt.getPrimaryTable().getTable() != joinTable) {
                        // Join to the join table
                        JavaTypeMapping referenceMapping = collTable.getElementMapping();
                        if (referenceMapping instanceof ReferenceMapping) {
                            // Join table has a reference mapping pointing to our table, so get the submapping for the implementation
                            ReferenceMapping refMap = (ReferenceMapping) referenceMapping;
                            Class implType = clr.classForName(mmd.getClassName(true));
                            referenceMapping = refMap.getJavaTypeMappingForType(implType);
                        }
                        joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), collTable, null, referenceMapping, null, tableGroupName + "_JOIN", true);
                    } else {
                        // Main table of the statement is the join table so no need to join
                        joinSqlTbl = stmt.getPrimaryTable();
                    }
                    // Select the owner mapping of the join table
                    int[] colNumbers = stmt.select(joinSqlTbl, selectMapping, null);
                    stmtMapping.setColumnPositions(colNumbers);
                }
            // TODO Select fetch plan fields of this related object
            } else if (relationType == RelationType.MANY_TO_ONE_UNI) {
                // Add left outer join from {sourceTable}.ID to {joinTable}.OWNER_FK
                PersistableJoinTable joinTable = (PersistableJoinTable) storeMgr.getTable(mmd);
                SQLTable joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), joinTable, null, joinTable.getOwnerMapping(), null, tableGroupName + "_JOIN", true);
                int[] colNumbers = stmt.select(joinSqlTbl, joinTable.getRelatedMapping(), null);
                stmtMapping.setColumnPositions(colNumbers);
            // TODO Select fetch plan fields of this related object
            }
        }
        if (mappingDefinition != null) {
            mappingDefinition.addMappingForMember(mmd.getAbsoluteFieldNumber(), stmtMapping);
        }
    }
}
Also used : FetchPlanForClass(org.datanucleus.FetchPlanForClass) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) RelationType(org.datanucleus.metadata.RelationType) List(java.util.List) ArrayList(java.util.ArrayList) ElementContainerTable(org.datanucleus.store.rdbms.table.ElementContainerTable) ElementContainerTable(org.datanucleus.store.rdbms.table.ElementContainerTable) PersistableJoinTable(org.datanucleus.store.rdbms.table.PersistableJoinTable) Table(org.datanucleus.store.rdbms.table.Table) JoinTable(org.datanucleus.store.rdbms.table.JoinTable) MetaDataManager(org.datanucleus.metadata.MetaDataManager) JoinType(org.datanucleus.store.rdbms.sql.SQLJoin.JoinType) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) FetchPlanForClass(org.datanucleus.FetchPlanForClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) PersistableJoinTable(org.datanucleus.store.rdbms.table.PersistableJoinTable) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

StatementMappingIndex (org.datanucleus.store.rdbms.query.StatementMappingIndex)66 ExecutionContext (org.datanucleus.ExecutionContext)49 StatementClassMapping (org.datanucleus.store.rdbms.query.StatementClassMapping)44 PreparedStatement (java.sql.PreparedStatement)37 SQLException (java.sql.SQLException)37 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)37 ManagedConnection (org.datanucleus.store.connection.ManagedConnection)37 SQLController (org.datanucleus.store.rdbms.SQLController)37 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)36 ResultSet (java.sql.ResultSet)32 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)28 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)21 ParameterSetter (org.datanucleus.store.rdbms.fieldmanager.ParameterSetter)21 PersistentClassROF (org.datanucleus.store.rdbms.query.PersistentClassROF)20 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)19 ResultObjectFactory (org.datanucleus.store.rdbms.query.ResultObjectFactory)19 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)18 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)18 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)15 DNStateManager (org.datanucleus.state.DNStateManager)15