Search in sources :

Example 66 with StatementMappingIndex

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

the class SQLStatementHelper method selectFetchPlanFieldsOfFKRelatedObject.

/**
 * Convenience method to join to and select all required FP fields of a related object where linked via an FK at this side.
 * Note that the FetchPlan can have null passed in here (27/04/2021) so cater for it.
 * @return Whether the caller should select the FK themselves (i.e we haven't selected anything)
 */
private static boolean selectFetchPlanFieldsOfFKRelatedObject(SelectStatement stmt, StatementClassMapping mappingDefinition, FetchPlan fetchPlan, SQLTable sourceSqlTbl, AbstractMemberMetaData mmd, ClassLoaderResolver clr, int maxFetchPlanLimit, JavaTypeMapping m, String tableGroupName, StatementMappingIndex stmtMapping, SQLTable sqlTbl, JoinType inputJoinType) {
    boolean selectFK = true;
    if (mmd.fetchFKOnly()) {
    // Only want FK fetching, and not the fields of the object (so avoid the join)
    } else {
        RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
        Class type = mmd.isSingleCollection() ? clr.classForName(mmd.getCollection().getElementType()) : mmd.getType();
        if (m instanceof ReferenceMapping) {
            ReferenceMapping refMapping = (ReferenceMapping) m;
            if (refMapping.getMappingStrategy() == ReferenceMapping.PER_IMPLEMENTATION_MAPPING && refMapping.getJavaTypeMapping().length == 1) {
                JavaTypeMapping[] subMappings = refMapping.getJavaTypeMapping();
                if (subMappings != null && subMappings.length == 1) {
                    // Special case of reference mapping with single FK implementation
                    type = clr.classForName(refMapping.getJavaTypeMapping()[0].getType());
                }
            }
        }
        // select fetch plan fields of this object
        AbstractClassMetaData relatedCmd = storeMgr.getMetaDataManager().getMetaDataForClass(type, clr);
        if (relatedCmd != null) {
            if (relatedCmd.isEmbeddedOnly()) {
                return true;
            }
            if (relatedCmd.getBaseAbstractClassMetaData().getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
                // Related object uses complete-table
                Collection<String> relSubclassNames = storeMgr.getSubClassesForClass(relatedCmd.getFullClassName(), true, clr);
                if (relatedCmd.isMappedSuperclass() && relSubclassNames.size() > 1) {
                    // Multiple possible related types and we don't have the FK so omit
                    return true;
                } else if (!relatedCmd.isMappedSuperclass() && relSubclassNames.size() > 0) {
                    // Multiple possible related types and we don't have the FK so omit
                    return true;
                }
            // TODO Maybe do a LEFT OUTER JOIN to each possible?
            }
            // Check if we are only fetching the PK field(s), in which case we can avoid any join
            if (fetchPlan != null) {
                FetchPlanForClass relatedFP = fetchPlan.getFetchPlanForClass(relatedCmd);
                int[] fpFieldNums = relatedFP.getMemberNumbers();
                if (relatedCmd.getIdentityType() == IdentityType.APPLICATION) {
                    int[] pkFieldNums = relatedCmd.getPKMemberPositions();
                    if (fpFieldNums != null && pkFieldNums != null && fpFieldNums.length == pkFieldNums.length) {
                        boolean equal = true;
                        for (int i = 0; i < fpFieldNums.length; i++) {
                            if (fpFieldNums[i] != pkFieldNums[i]) {
                                equal = false;
                                break;
                            }
                        }
                        if (equal) {
                            // Solely fetching the PK fields, so no need to join (just like fetchFkOnly case above)
                            return true;
                        }
                    }
                } else if (relatedCmd.getIdentityType() == IdentityType.DATASTORE) {
                    if (fpFieldNums == null || fpFieldNums.length == 0) {
                        return true;
                    }
                }
            }
            // Find the table of the related class
            DatastoreClass relatedTbl = storeMgr.getDatastoreClass(relatedCmd.getFullClassName(), clr);
            if (relatedTbl == null) {
                // Class doesn't have its own table (subclass-table) so find where it persists
                AbstractClassMetaData[] ownerParentCmds = storeMgr.getClassesManagingTableForClass(relatedCmd, clr);
                if (ownerParentCmds.length > 1) {
                    // TODO Fix this
                    NucleusLogger.QUERY.warn("Relation (" + mmd.getFullFieldName() + ") with multiple related tables (using subclass-table). Not supported so selecting FK of related object only");
                    return true;
                }
                relatedTbl = storeMgr.getDatastoreClass(ownerParentCmds[0].getFullClassName(), clr);
            }
            String requiredGroupName = null;
            if (sourceSqlTbl.getGroupName() != null) {
                // JPQL will have table groups defined already, named as per "alias.fieldName"
                requiredGroupName = sourceSqlTbl.getGroupName() + "." + mmd.getName();
            }
            SQLTable relatedSqlTbl = stmt.getTable(relatedTbl, requiredGroupName);
            if (relatedSqlTbl == null) {
                // Join the 1-1 relation
                JoinType joinType = getJoinTypeForOneToOneRelationJoin(m, sqlTbl, inputJoinType);
                if (joinType == JoinType.LEFT_OUTER_JOIN || joinType == JoinType.RIGHT_OUTER_JOIN) {
                    inputJoinType = joinType;
                }
                relatedSqlTbl = addJoinForOneToOneRelation(stmt, m, sqlTbl, relatedTbl.getIdMapping(), relatedTbl, null, null, tableGroupName, joinType);
            }
            StatementClassMapping subMappingDefinition = new StatementClassMapping(mmd.getClassName(), mmd.getName());
            selectFetchPlanOfSourceClassInStatement(stmt, subMappingDefinition, fetchPlan, relatedSqlTbl, relatedCmd, maxFetchPlanLimit - 1, inputJoinType);
            if (mappingDefinition != null) {
                if (relatedCmd.getIdentityType() == IdentityType.APPLICATION) {
                    int[] pkFields = relatedCmd.getPKMemberPositions();
                    int[] pkCols = new int[m.getNumberOfColumnMappings()];
                    int pkColNo = 0;
                    for (int pkField : pkFields) {
                        StatementMappingIndex pkIdx = subMappingDefinition.getMappingForMemberPosition(pkField);
                        int[] pkColNumbers = pkIdx.getColumnPositions();
                        for (int pkColNumber : pkColNumbers) {
                            pkCols[pkColNo] = pkColNumber;
                            pkColNo++;
                        }
                    }
                    selectFK = false;
                    stmtMapping.setColumnPositions(pkCols);
                } else if (relatedCmd.getIdentityType() == IdentityType.DATASTORE) {
                    StatementMappingIndex pkIdx = subMappingDefinition.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
                    selectFK = false;
                    stmtMapping.setColumnPositions(pkIdx.getColumnPositions());
                }
                mappingDefinition.addMappingDefinitionForMember(mmd.getAbsoluteFieldNumber(), subMappingDefinition);
            }
        } else {
        // TODO 1-1 interface relation
        }
    }
    return selectFK;
}
Also used : FetchPlanForClass(org.datanucleus.FetchPlanForClass) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) JoinType(org.datanucleus.store.rdbms.sql.SQLJoin.JoinType) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) FetchPlanForClass(org.datanucleus.FetchPlanForClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass)

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