Search in sources :

Example 11 with DatastoreClass

use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.

the class QueryToSQLMapper method getSQLTableMappingForPrimaryExpression.

/**
 * Method to take in a PrimaryExpression and return the SQLTable mapping info that it signifies.
 * If the primary expression implies joining to other objects then adds the joins to the statement.
 * Only adds joins if necessary; so if there is a further component after the required join, or if
 * the "forceJoin" flag is set.
 * @param theStmt SQLStatement to use when looking for tables etc
 * @param exprName Name for an expression that this primary is relative to (optional)
 *                 If not specified then the tuples are relative to the candidate.
 *                 If specified then should have an entry in sqlTableByPrimary under this name.
 * @param primExpr The primary expression
 * @param forceJoin Whether to force a join if a relation member (or null if leaving to this method to decide)
 * @return The SQL table mapping information for the specified primary
 */
private SQLTableMapping getSQLTableMappingForPrimaryExpression(SQLStatement theStmt, String exprName, PrimaryExpression primExpr, Boolean forceJoin) {
    if (forceJoin == null && primExpr.getParent() != null) {
        if (primExpr.getParent().getOperator() == Expression.OP_IS || primExpr.getParent().getOperator() == Expression.OP_ISNOT) {
            // "instanceOf" needs to be in the table of the primary expression
            forceJoin = Boolean.TRUE;
        }
    }
    SQLTableMapping sqlMapping = null;
    List<String> tuples = primExpr.getTuples();
    // Find source object
    ListIterator<String> iter = tuples.listIterator();
    String first = tuples.get(0);
    boolean mapKey = false;
    boolean mapValue = false;
    if (first.endsWith("#KEY")) {
        first = first.substring(0, first.length() - 4);
        mapKey = true;
    } else if (first.endsWith("#VALUE")) {
        first = first.substring(0, first.length() - 6);
        mapValue = true;
    }
    String primaryName = null;
    if (exprName != null) {
        // Primary relative to some object etc
        sqlMapping = getSQLTableMappingForAlias(exprName);
        primaryName = exprName;
    } else {
        if (hasSQLTableMappingForAlias(first)) {
            // Start from a candidate (e.g JPQL alias)
            sqlMapping = getSQLTableMappingForAlias(first);
            primaryName = first;
            // Skip first tuple
            iter.next();
        }
        if (sqlMapping != null && first.equals(candidateAlias) && candidateCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
            // Special case of using COMPLETE_TABLE for candidate and picked wrong table
            // TODO Use OPTION_CASE_INSENSITIVE
            SQLTable firstSqlTbl = stmt.getTable(first.toUpperCase());
            if (firstSqlTbl != null && firstSqlTbl.getTable() != sqlMapping.table.getTable()) {
                // Cached the SQLTableMapping for one of the other inherited classes, so create our own
                sqlMapping = new SQLTableMapping(firstSqlTbl, sqlMapping.cmd, firstSqlTbl.getTable().getIdMapping());
            }
        }
        if (sqlMapping == null) {
            if (parentMapper != null) {
                QueryToSQLMapper theParentMapper = parentMapper;
                while (theParentMapper != null) {
                    if (theParentMapper.hasSQLTableMappingForAlias(first)) {
                        // Try parent query
                        sqlMapping = theParentMapper.getSQLTableMappingForAlias(first);
                        primaryName = first;
                        // Skip first tuple
                        iter.next();
                        // This expression is for the parent statement so any joins need to go on that statement
                        theStmt = sqlMapping.table.getSQLStatement();
                        break;
                    }
                    theParentMapper = theParentMapper.parentMapper;
                }
            }
        }
        if (sqlMapping == null) {
            // Field of candidate, so use candidate
            sqlMapping = getSQLTableMappingForAlias(candidateAlias);
            primaryName = candidateAlias;
        }
    }
    AbstractClassMetaData cmd = sqlMapping.cmd;
    JavaTypeMapping mapping = sqlMapping.mapping;
    if (sqlMapping.mmd != null && (mapKey || mapValue)) {
        // Special case of MAP#KEY or MAP#VALUE, so navigate from the Map "table" to the key or value
        SQLTable sqlTbl = sqlMapping.table;
        AbstractMemberMetaData mmd = sqlMapping.mmd;
        MapMetaData mapmd = mmd.getMap();
        // Find the table forming the Map. This may be a join table, or the key or value depending on the type
        if (mapKey) {
            // Cater for all case possibilities of table name/alias
            // TODO Use OPTION_CASE_INSENSITIVE
            SQLTable mapSqlTbl = stmt.getTable(first + "_MAP");
            if (mapSqlTbl == null) {
                mapSqlTbl = stmt.getTable((first + "_MAP").toUpperCase());
                if (mapSqlTbl == null) {
                    mapSqlTbl = stmt.getTable((first + "_MAP").toLowerCase());
                }
            }
            if (mapSqlTbl != null) {
                sqlTbl = mapSqlTbl;
            }
        }
        if (mapmd.getMapType() == MapType.MAP_TYPE_JOIN) {
            if (sqlTbl.getTable() instanceof MapTable) {
                MapTable mapTable = (MapTable) sqlTbl.getTable();
                if (mapKey) {
                    cmd = mapmd.getKeyClassMetaData(clr);
                    if (!mapmd.isEmbeddedKey() && !mapmd.isSerializedKey()) {
                        // Join to key table
                        DatastoreClass keyTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
                        sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapTable.getKeyMapping(), keyTable, null, keyTable.getIdMapping(), null, null, true);
                        mapping = keyTable.getIdMapping();
                    } else {
                        mapping = mapTable.getKeyMapping();
                    }
                } else {
                    cmd = mapmd.getValueClassMetaData(clr);
                    if (!mapmd.isEmbeddedValue() && !mapmd.isSerializedValue()) {
                        // Join to value table
                        DatastoreClass valueTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
                        sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapTable.getValueMapping(), valueTable, null, valueTable.getIdMapping(), null, null, true);
                        mapping = valueTable.getIdMapping();
                    } else {
                        mapping = mapTable.getValueMapping();
                    }
                }
            } else {
                // TODO Document exactly which situation this is
                if (!mapmd.isEmbeddedValue() && !mapmd.isSerializedValue()) {
                    mapping = sqlTbl.getTable().getIdMapping();
                }
            }
        } else if (mapmd.getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE) {
            if (mapKey) {
                AbstractClassMetaData keyCmd = mapmd.getKeyClassMetaData(clr);
                String keyMappedBy = mmd.getKeyMetaData().getMappedBy();
                mapping = ((DatastoreClass) sqlTbl.getTable()).getMemberMapping(keyMappedBy);
                if (keyCmd != null) {
                    // Join to key table
                    DatastoreClass keyTable = storeMgr.getDatastoreClass(mapmd.getKeyType(), clr);
                    sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapping, keyTable, null, keyTable.getIdMapping(), null, null, true);
                    mapping = keyTable.getIdMapping();
                }
            } else {
            }
        } else if (mapmd.getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY) {
            // TODO We maybe already have the VALUE TABLE from the original join
            if (!mapKey) {
                AbstractClassMetaData valCmd = mapmd.getValueClassMetaData(clr);
                String valMappedBy = mmd.getValueMetaData().getMappedBy();
                mapping = ((DatastoreClass) sqlTbl.getTable()).getMemberMapping(valMappedBy);
                if (valCmd != null) {
                    // Join to value table
                    DatastoreClass valueTable = storeMgr.getDatastoreClass(mapmd.getValueType(), clr);
                    sqlTbl = stmt.join(getDefaultJoinTypeForNavigation(), sqlMapping.table, mapping, valueTable, null, valueTable.getIdMapping(), null, null, true);
                    mapping = valueTable.getIdMapping();
                }
            }
        }
        sqlMapping = new SQLTableMapping(sqlTbl, cmd, mapping);
    }
    while (iter.hasNext()) {
        String component = iter.next();
        // fully-qualified primary name
        primaryName += "." + component;
        // Derive SQLTableMapping for this component
        SQLTableMapping sqlMappingNew = getSQLTableMappingForAlias(primaryName);
        if (sqlMappingNew == null) {
            // Table not present for this primary
            AbstractMemberMetaData mmd = cmd.getMetaDataForMember(component);
            if (mmd == null) {
                // Not valid member name
                throw new NucleusUserException(Localiser.msg("021062", component, cmd.getFullClassName()));
            } else if (mmd.getPersistenceModifier() != FieldPersistenceModifier.PERSISTENT) {
                throw new NucleusUserException("Field " + mmd.getFullFieldName() + " is not marked as persistent so cannot be queried");
            }
            RelationType relationType = mmd.getRelationType(clr);
            // Find the table and the mapping for this field in the table
            SQLTable sqlTbl = null;
            if (mapping instanceof EmbeddedMapping) {
                // Embedded into the current table
                sqlTbl = sqlMapping.table;
                mapping = ((EmbeddedMapping) mapping).getJavaTypeMapping(component);
            } else if (mapping instanceof PersistableMapping && cmd.isEmbeddedOnly()) {
                // JPA EmbeddedId into current table
                sqlTbl = sqlMapping.table;
                JavaTypeMapping[] subMappings = ((PersistableMapping) mapping).getJavaTypeMapping();
                if (subMappings.length == 1 && subMappings[0] instanceof EmbeddedPCMapping) {
                    mapping = ((EmbeddedPCMapping) subMappings[0]).getJavaTypeMapping(component);
                } else {
                // TODO What situation is this?
                }
            } else {
                DatastoreClass table = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr);
                if (table == null) {
                    if (cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE && candidateCmd.getFullClassName().equals(cmd.getFullClassName())) {
                        // Special case of a candidate having no table of its own and using COMPLETE_TABLE, so we use the candidate class for this statement (or UNION)
                        table = storeMgr.getDatastoreClass(stmt.getCandidateClassName(), clr);
                    }
                }
                if (table == null) {
                    AbstractClassMetaData[] subCmds = storeMgr.getClassesManagingTableForClass(cmd, clr);
                    if (subCmds.length == 1) {
                        table = storeMgr.getDatastoreClass(subCmds[0].getFullClassName(), clr);
                    } else {
                        // all of UNIONs, and this primary expression refers to a mapping in each of subclass tables
                        throw new NucleusUserException("Unable to find table for primary " + primaryName + " since the class " + cmd.getFullClassName() + " is managed in multiple tables");
                    }
                }
                if (table == null) {
                    throw new NucleusUserException("Unable to find table for primary " + primaryName + ". Table for class=" + cmd.getFullClassName() + " is null : is the field correct? or using some inheritance pattern?");
                }
                mapping = table.getMemberMapping(mmd);
                sqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(theStmt, sqlMapping.table, mapping);
            }
            if (relationType == RelationType.NONE) {
                sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, mapping);
                cmd = sqlMappingNew.cmd;
                setSQLTableMappingForAlias(primaryName, sqlMappingNew);
            } else if (relationType == RelationType.ONE_TO_ONE_UNI || relationType == RelationType.ONE_TO_ONE_BI) {
                if (mmd.getMappedBy() != null) {
                    // FK in other table so join to that first
                    AbstractMemberMetaData relMmd = mmd.getRelatedMemberMetaData(clr)[0];
                    if (relMmd.getAbstractClassMetaData().isEmbeddedOnly()) {
                        // Member is embedded, so keep same SQL table mapping
                        sqlMappingNew = sqlMapping;
                        cmd = relMmd.getAbstractClassMetaData();
                    } else {
                        // Member is in own table, so move to that SQL table mapping
                        DatastoreClass relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
                        JavaTypeMapping relMapping = relTable.getMemberMapping(relMmd);
                        // Join to related table unless we already have the join in place
                        sqlTbl = theStmt.getTable(relTable, primaryName);
                        if (sqlTbl == null) {
                            sqlTbl = SQLStatementHelper.addJoinForOneToOneRelation(theStmt, sqlMapping.table.getTable().getIdMapping(), sqlMapping.table, relMapping, relTable, null, null, primaryName, getDefaultJoinTypeForNavigation());
                        }
                        if (iter.hasNext()) {
                            sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
                            cmd = sqlMappingNew.cmd;
                        } else {
                            sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, relTable.getIdMapping());
                            cmd = sqlMappingNew.cmd;
                        }
                    }
                } else {
                    // FK is at this side
                    if (forceJoin == null) {
                        if (!iter.hasNext()) {
                            // Further component provided, so check if we should force a join to the other side
                            if (primExpr.getParent() != null && primExpr.getParent().getOperator() == Expression.OP_CAST) {
                                // Cast and not an interface field, so do a join to the table of the persistable object
                                if (mapping instanceof ReferenceMapping) {
                                // Don't join with interface field since represents multiple implementations
                                // and the cast will be a restrict on which implementation to join to
                                } else {
                                    AbstractClassMetaData relCmd = ec.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
                                    if (relCmd != null && !relCmd.isEmbeddedOnly()) {
                                        DatastoreClass relTable = storeMgr.getDatastoreClass(relCmd.getFullClassName(), clr);
                                        if (relTable == null) {
                                        } else {
                                            forceJoin = Boolean.TRUE;
                                        }
                                    } else {
                                        forceJoin = Boolean.TRUE;
                                    }
                                }
                            }
                        } else {
                            // TODO Add optimisation to omit join if the FK is at this side and only selecting PK of the related object
                            if (iter.hasNext()) {
                                // Peek ahead to see if just selecting "id" of the related (i.e candidate.related.id with related FK in candidate table, so don't join)
                                String next = iter.next();
                                if (!iter.hasNext()) {
                                    AbstractClassMetaData relCmd = storeMgr.getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
                                    if (relCmd != null) {
                                        AbstractMemberMetaData mmdOfRelCmd = relCmd.getMetaDataForMember(next);
                                        if (mmdOfRelCmd != null && mmdOfRelCmd.isPrimaryKey() && relCmd.getNoOfPrimaryKeyMembers() == 1 && !storeMgr.getMetaDataManager().isClassPersistable(mmdOfRelCmd.getTypeName())) {
                                            // We have something like "a.b.id" and have the FK to the "B" table in the "A" table, so just refer to A.FK rather than joining and using B.ID
                                            NucleusLogger.QUERY.debug("Found implicit join to member=" + mmdOfRelCmd.getFullFieldName() + " which is PK of the other type but FK is in this table so avoiding the join");
                                            JavaTypeMapping subMapping = ((PersistableMapping) mapping).getJavaTypeMapping()[0];
                                            // Component mappings of a PersistableMapping sometimes don't have table set, so fix it
                                            subMapping.setTable(mapping.getTable());
                                            return new SQLTableMapping(sqlMapping.table, relCmd, subMapping);
                                        }
                                    }
                                }
                                iter.previous();
                            }
                        }
                    }
                    if (iter.hasNext() || Boolean.TRUE.equals(forceJoin)) {
                        AbstractClassMetaData relCmd = null;
                        JavaTypeMapping relMapping = null;
                        DatastoreClass relTable = null;
                        if (relationType == RelationType.ONE_TO_ONE_BI) {
                            AbstractMemberMetaData relMmd = mmd.getRelatedMemberMetaData(clr)[0];
                            relCmd = relMmd.getAbstractClassMetaData();
                        } else {
                            String typeName = mmd.isSingleCollection() ? mmd.getCollection().getElementType() : mmd.getTypeName();
                            relCmd = ec.getMetaDataManager().getMetaDataForClass(typeName, clr);
                        }
                        if (relCmd != null && relCmd.isEmbeddedOnly()) {
                            // Member is embedded so use same table but embedded mapping
                            sqlMappingNew = new SQLTableMapping(sqlTbl, relCmd, mapping);
                            cmd = relCmd;
                        } else {
                            // Member is in own table, so move to that SQL table mapping
                            relTable = storeMgr.getDatastoreClass(relCmd.getFullClassName(), clr);
                            if (relTable == null) {
                                // No table for the related type (subclass-table), so see if this class has a single subclass with its own table
                                Collection<String> relSubclassNames = storeMgr.getSubClassesForClass(relCmd.getFullClassName(), false, clr);
                                if (relSubclassNames != null && relSubclassNames.size() == 1) {
                                    String relSubclassName = relSubclassNames.iterator().next();
                                    relTable = storeMgr.getDatastoreClass(relSubclassName, clr);
                                    // TODO Cater for this having no table and next level yes etc
                                    if (relTable != null) {
                                        relCmd = ec.getMetaDataManager().getMetaDataForClass(relSubclassName, clr);
                                    }
                                }
                                if (relTable == null) {
                                    // No table as such, so likely using subclass-table at other side and we don't know where to join to
                                    throw new NucleusUserException("Reference to PrimaryExpression " + primExpr + " yet this needs to join relation " + mmd.getFullFieldName() + " and the other type has no table (subclass-table?). Maybe use a CAST to the appropriate subclass?");
                                }
                            }
                            relMapping = relTable.getIdMapping();
                            // Join to other table unless we already have the join in place
                            sqlTbl = theStmt.getTable(relTable, primaryName);
                            if (sqlTbl == null) {
                                sqlTbl = SQLStatementHelper.addJoinForOneToOneRelation(theStmt, mapping, sqlMapping.table, relMapping, relTable, null, null, primaryName, getDefaultJoinTypeForNavigation());
                            }
                            sqlMappingNew = new SQLTableMapping(sqlTbl, relCmd, relMapping);
                            cmd = sqlMappingNew.cmd;
                            setSQLTableMappingForAlias(primaryName, sqlMappingNew);
                        }
                    } else {
                        sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, mapping);
                        cmd = sqlMappingNew.cmd;
                    // Don't register the SQLTableMapping for this alias since only using FK
                    }
                }
            } else if (relationType == RelationType.MANY_TO_ONE_BI) {
                AbstractMemberMetaData relMmd = mmd.getRelatedMemberMetaData(clr)[0];
                DatastoreClass relTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
                if (mmd.getJoinMetaData() != null || relMmd.getJoinMetaData() != null) {
                    // Has join table so use that
                    sqlTbl = theStmt.getTable(relTable, primaryName);
                    if (sqlTbl == null) {
                        // Join to the join table
                        CollectionTable joinTbl = (CollectionTable) storeMgr.getTable(relMmd);
                        JoinType defJoinType = getDefaultJoinTypeForNavigation();
                        if (defJoinType == JoinType.INNER_JOIN) {
                            SQLTable joinSqlTbl = theStmt.join(JoinType.INNER_JOIN, sqlMapping.table, sqlMapping.table.getTable().getIdMapping(), joinTbl, null, joinTbl.getElementMapping(), null, null, true);
                            sqlTbl = theStmt.join(JoinType.INNER_JOIN, joinSqlTbl, joinTbl.getOwnerMapping(), relTable, null, relTable.getIdMapping(), null, primaryName, true);
                        } else if (defJoinType == JoinType.LEFT_OUTER_JOIN || defJoinType == null) {
                            SQLTable joinSqlTbl = theStmt.join(JoinType.LEFT_OUTER_JOIN, sqlMapping.table, sqlMapping.table.getTable().getIdMapping(), joinTbl, null, joinTbl.getElementMapping(), null, null, true);
                            sqlTbl = theStmt.join(JoinType.LEFT_OUTER_JOIN, joinSqlTbl, joinTbl.getOwnerMapping(), relTable, null, relTable.getIdMapping(), null, primaryName, true);
                        }
                    }
                    sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
                    cmd = sqlMappingNew.cmd;
                    setSQLTableMappingForAlias(primaryName, sqlMappingNew);
                } else {
                    // FK in this table
                    sqlTbl = theStmt.getTable(relTable, primaryName);
                    if (sqlTbl == null) {
                        if (mmd.getMappedBy() == null) {
                            // FK at this side so check for optimisations
                            if (iter.hasNext()) {
                                // Peek ahead to see if just selecting "id" of the related (i.e candidate.related.id with related FK in candidate table, so don't join)
                                String next = iter.next();
                                if (!iter.hasNext()) {
                                    AbstractClassMetaData relCmd = relMmd.getAbstractClassMetaData();
                                    AbstractMemberMetaData mmdOfRelCmd = relCmd.getMetaDataForMember(next);
                                    if (mmdOfRelCmd != null && mmdOfRelCmd.isPrimaryKey() && relCmd.getNoOfPrimaryKeyMembers() == 1 && !storeMgr.getMetaDataManager().isClassPersistable(mmdOfRelCmd.getTypeName())) {
                                        // We have something like "a.b.id" and have the FK to the "B" table in the "A" table, so just refer to A.FK rather than joining and using B.ID
                                        NucleusLogger.QUERY.debug("Found implicit join to member=" + mmdOfRelCmd.getFullFieldName() + " which is PK of the other type but FK is in this table so avoiding the join");
                                        JavaTypeMapping subMapping = ((PersistableMapping) mapping).getJavaTypeMapping()[0];
                                        // Component mappings of a PersistableMapping sometimes don't have table set, so fix it
                                        subMapping.setTable(mapping.getTable());
                                        return new SQLTableMapping(sqlMapping.table, relCmd, subMapping);
                                    }
                                }
                                iter.previous();
                            }
                        }
                        Operator op = (primExpr.getParent() != null ? primExpr.getParent().getOperator() : null);
                        if (!iter.hasNext() && (op == Expression.OP_EQ || op == Expression.OP_GT || op == Expression.OP_LT || op == Expression.OP_GTEQ || op == Expression.OP_LTEQ || op == Expression.OP_NOTEQ)) {
                            // Just return the FK mapping since in a "a.b == c.d" type expression and not needing to go further than the FK
                            sqlMappingNew = new SQLTableMapping(sqlMapping.table, relMmd.getAbstractClassMetaData(), mapping);
                        } else {
                            // Join to the related table
                            JoinType defJoinType = getDefaultJoinTypeForNavigation();
                            if (defJoinType == JoinType.INNER_JOIN) {
                                sqlTbl = theStmt.join(JoinType.INNER_JOIN, sqlMapping.table, mapping, relTable, null, relTable.getIdMapping(), null, primaryName, true);
                            } else if (defJoinType == JoinType.LEFT_OUTER_JOIN || defJoinType == null) {
                                sqlTbl = theStmt.join(JoinType.LEFT_OUTER_JOIN, sqlMapping.table, mapping, relTable, null, relTable.getIdMapping(), null, primaryName, true);
                            }
                            sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
                            cmd = sqlMappingNew.cmd;
                            setSQLTableMappingForAlias(primaryName, sqlMappingNew);
                        }
                    } else {
                        sqlMappingNew = new SQLTableMapping(sqlTbl, relMmd.getAbstractClassMetaData(), relTable.getIdMapping());
                        cmd = sqlMappingNew.cmd;
                        setSQLTableMappingForAlias(primaryName, sqlMappingNew);
                    }
                }
            } else if (RelationType.isRelationMultiValued(relationType)) {
                // Can't reference further than a collection/map so just return its mapping here
                sqlMappingNew = new SQLTableMapping(sqlTbl, cmd, mapping);
                cmd = sqlMappingNew.cmd;
                setSQLTableMappingForAlias(primaryName, sqlMappingNew);
            }
        } else {
            cmd = sqlMappingNew.cmd;
        }
        sqlMapping = sqlMappingNew;
    }
    return sqlMapping;
}
Also used : Operator(org.datanucleus.query.expression.Expression.Operator) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) EmbeddedPCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedPCMapping) JoinType(org.datanucleus.store.rdbms.sql.SQLJoin.JoinType) MapMetaData(org.datanucleus.metadata.MapMetaData) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) MapTable(org.datanucleus.store.rdbms.table.MapTable) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) CollectionTable(org.datanucleus.store.rdbms.table.CollectionTable) EmbeddedMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedMapping) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) RelationType(org.datanucleus.metadata.RelationType) Collection(java.util.Collection) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 12 with DatastoreClass

use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.

the class FetchRequest method processMembersOfClass.

/**
 * Method to process the supplied members of the class, adding to the SQLStatement as required.
 * Can recurse if some of the requested fields are persistent objects in their own right, so we
 * take the opportunity to retrieve some of their fields.
 * @param sqlStatement Statement being built
 * @param mmds Meta-data for the required fields/properties
 * @param table The table to look for member mappings
 * @param sqlTbl The table in the SQL statement to use for selects
 * @param mappingDef Mapping definition for the result
 * @param fetchCallbacks Any additional required callbacks are added here
 * @param clr ClassLoader resolver
 * @return Number of fields being fetched
 */
protected int processMembersOfClass(SelectStatement sqlStatement, AbstractMemberMetaData[] mmds, DatastoreClass table, SQLTable sqlTbl, StatementClassMapping mappingDef, Collection fetchCallbacks, ClassLoaderResolver clr) {
    int number = 0;
    if (mmds != null) {
        for (int i = 0; i < mmds.length; i++) {
            // Get the mapping (in this table, or super-table)
            AbstractMemberMetaData mmd = mmds[i];
            JavaTypeMapping mapping = table.getMemberMapping(mmd);
            if (mapping != null) {
                if (!mmd.isPrimaryKey() && mapping.includeInFetchStatement()) {
                    // The depth is the number of levels down to load in this statement.
                    // 0 is to load just this objects fields (as with JPOX, and DataNucleus up to 1.1.3)
                    int depth = 0;
                    AbstractMemberMetaData mmdToUse = mmd;
                    JavaTypeMapping mappingToUse = mapping;
                    if (mapping instanceof SingleCollectionMapping) {
                        // Check the wrapped type
                        mappingToUse = ((SingleCollectionMapping) mapping).getWrappedMapping();
                        mmdToUse = ((SingleCollectionMapping) mapping).getWrappedMapping().getMemberMetaData();
                    }
                    if (mappingToUse instanceof PersistableMapping) {
                        // Special case of 1-1/N-1 where we know the other side type so know what to join to, hence can load the related object
                        depth = 1;
                        if (Modifier.isAbstract(mmdToUse.getType().getModifiers())) {
                            String typeName = mmdToUse.getTypeName();
                            DatastoreClass relTable = table.getStoreManager().getDatastoreClass(typeName, clr);
                            if (relTable != null && relTable.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, false) == null) {
                                // 1-1 relation to base class with no discriminator and has subclasses
                                // hence no way of determining the exact type, hence no point in fetching it
                                String[] subclasses = table.getStoreManager().getMetaDataManager().getSubclassesForClass(typeName, false);
                                if (subclasses != null && subclasses.length > 0) {
                                    depth = 0;
                                }
                            }
                        }
                    } else if (mappingToUse instanceof ReferenceMapping) {
                        ReferenceMapping refMapping = (ReferenceMapping) mappingToUse;
                        if (refMapping.getMappingStrategy() == ReferenceMapping.PER_IMPLEMENTATION_MAPPING) {
                            JavaTypeMapping[] subMappings = refMapping.getJavaTypeMapping();
                            if (subMappings != null && subMappings.length == 1) {
                                // Support special case of reference mapping with single implementation possible
                                depth = 1;
                            }
                        }
                    }
                    // TODO We should use the actual FetchPlan, and the max fetch depth, so then it can pull in all related objects within reach.
                    // But this will mean we cannot cache the statement, since it is for a specific ExecutionContext
                    // TODO If this field is a 1-1 and the other side has a discriminator or version then we really ought to fetch it
                    SQLStatementHelper.selectMemberOfSourceInStatement(sqlStatement, mappingDef, null, sqlTbl, mmd, clr, depth, null);
                    number++;
                }
                if (mapping instanceof MappingCallbacks) {
                    // TODO Need to add that this mapping is for base object or base.field1, etc
                    fetchCallbacks.add(mapping);
                }
            }
        }
    }
    JavaTypeMapping versionMapping = table.getSurrogateMapping(SurrogateColumnType.VERSION, true);
    if (versionMapping != null) {
        // Select version
        StatementMappingIndex verMapIdx = new StatementMappingIndex(versionMapping);
        SQLTable verSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStatement, sqlTbl, versionMapping);
        int[] cols = sqlStatement.select(verSqlTbl, versionMapping, null);
        verMapIdx.setColumnPositions(cols);
        mappingDef.addMappingForMember(SurrogateColumnType.VERSION.getFieldNumber(), verMapIdx);
    }
    return number;
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) MappingCallbacks(org.datanucleus.store.rdbms.mapping.MappingCallbacks) SingleCollectionMapping(org.datanucleus.store.rdbms.mapping.java.SingleCollectionMapping) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 13 with DatastoreClass

use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.

the class ReferenceMapping method createPerImplementationColumnsForReferenceField.

/**
 * Create columns for reference (Interface/Object) fields on a per-implementation basis.
 * This call ColumnCreator.createColumnsForField for each implementation class of the reference.
 */
void createPerImplementationColumnsForReferenceField(boolean pk, boolean nullable, boolean serialised, boolean embedded, FieldRole fieldRole, ColumnMetaData[] columnMetaData, ClassLoaderResolver clr) {
    if (this instanceof InterfaceMapping && mmd.hasExtension(MetaData.EXTENSION_MEMBER_IMPLEMENTATION_CLASSES)) {
        // Store the implementation-classes with the mapping (persistent interfaces?)
        ((InterfaceMapping) this).setImplementationClasses(mmd.getValueForExtension(MetaData.EXTENSION_MEMBER_IMPLEMENTATION_CLASSES));
    }
    // Find the available implementations that we are creating columns for
    String[] implTypes = null;
    try {
        implTypes = MetaDataUtils.getInstance().getImplementationNamesForReferenceField(mmd, fieldRole, clr, storeMgr.getMetaDataManager());
    } catch (NucleusUserException nue) {
        // No implementation classes found, so log warning and return
        if (storeMgr.getBooleanProperty(PropertyNames.PROPERTY_STORE_ALLOW_REFS_WITHOUT_IMPLS, false)) {
            NucleusLogger.DATASTORE_SCHEMA.warn("Possible problem encountered while adding columns for field " + mmd.getFullFieldName() + " : " + nue.getMessage());
            return;
        }
        throw nue;
    }
    // Set the PK and nullability of column(s) for the implementations (based on the number of impls etc)
    if (implTypes.length > 1) {
        // Cannot be part of PK if more than 1 implementation
        pk = false;
    }
    if (implTypes.length > 1 && !pk) {
        // Must be nullable if more than 1 impl (since only 1 impl can have value at a time)
        nullable = true;
    }
    // Create list of classes that require columns.
    // We only add columns for the implementation that is the root of a particular inheritance tree
    // e.g if we have A implements I1, and B extends A then they both are valid implementations
    // but we only want to create column(s) for A.
    Collection implClasses = new ArrayList();
    for (int i = 0; i < implTypes.length; i++) {
        Class type = clr.classForName(implTypes[i]);
        if (type == null) {
            throw new NucleusUserException(Localiser.msg("020189", mmd.getTypeName(), implTypes[i]));
        } else if (type.isInterface()) {
            throw new NucleusUserException(Localiser.msg("020190", mmd.getFullFieldName(), mmd.getTypeName(), implTypes[i]));
        }
        Iterator iter = implClasses.iterator();
        boolean toBeAdded = true;
        Class clsToSwap = null;
        while (iter.hasNext()) {
            Class cls = (Class) iter.next();
            if (cls == type) {
                // Implementation already present
                toBeAdded = false;
                break;
            }
            if (type.isAssignableFrom(cls)) {
                // "type" is superclass of "cls" so swap subclass for this class
                clsToSwap = cls;
                toBeAdded = false;
                break;
            } else if (cls.isAssignableFrom(type)) {
                toBeAdded = false;
                break;
            }
        }
        if (toBeAdded) {
            implClasses.add(type);
        } else if (clsToSwap != null) {
            implClasses.remove(clsToSwap);
            implClasses.add(type);
        }
    }
    // Add columns for each of these implementations
    int colPos = 0;
    Iterator implClsIter = implClasses.iterator();
    while (implClsIter.hasNext()) {
        Class implClass = (Class) implClsIter.next();
        boolean present = false;
        int numJavaTypeMappings = getJavaTypeMapping().length;
        for (int i = 0; i < numJavaTypeMappings; i++) {
            JavaTypeMapping implMapping = getJavaTypeMapping()[i];
            if (implClass.getName().equals(implMapping.getType())) {
                present = true;
            }
        }
        if (present) {
            // Implementation already present in mapping (e.g reinitialising) so skip this
            continue;
        }
        String fieldTypeName = getReferenceFieldType(fieldRole);
        boolean isPersistentInterfaceField = storeMgr.getNucleusContext().getMetaDataManager().isPersistentInterface(fieldTypeName);
        boolean columnsNeeded = true;
        if (isPersistentInterfaceField && !storeMgr.getNucleusContext().getMetaDataManager().isPersistentInterfaceImplementation(fieldTypeName, implClass.getName())) {
            // We have a "persistent-interface" field yet this is not a generated implementation so ignore it
            // It is arguable if we should allow the real implementations of this interface here, but the JDO2 TCK doesn't
            // make that assumption so we don't either
            columnsNeeded = false;
        }
        if (columnsNeeded) {
            // Get the mapping for this implementation
            JavaTypeMapping m;
            if (storeMgr.getMappingManager().isSupportedMappedType(implClass.getName())) {
                m = storeMgr.getMappingManager().getMapping(implClass, serialised, embedded, mmd.getFullFieldName());
            } else {
                try {
                    DatastoreClass dc = storeMgr.getDatastoreClass(implClass.getName(), clr);
                    m = dc.getIdMapping();
                } catch (NoTableManagedException ex) {
                    // TODO Localise this message
                    throw new NucleusUserException("Cannot define columns for " + mmd.getFullFieldName() + " due to " + ex.getMessage(), ex);
                }
            }
            ColumnMetaData[] columnMetaDataForType = null;
            if (columnMetaData != null && columnMetaData.length > 0) {
                if (columnMetaData.length < colPos + m.getNumberOfDatastoreMappings()) {
                    throw new NucleusUserException(Localiser.msg("020186", mmd.getFullFieldName(), "" + columnMetaData.length, "" + (colPos + m.getNumberOfDatastoreMappings())));
                }
                columnMetaDataForType = new ColumnMetaData[m.getNumberOfDatastoreMappings()];
                System.arraycopy(columnMetaData, colPos, columnMetaDataForType, 0, columnMetaDataForType.length);
                colPos += columnMetaDataForType.length;
            }
            // Create the FK column(s) for this implementation
            ColumnCreator.createColumnsForField(implClass, this, table, storeMgr, mmd, pk, nullable, serialised, embedded, fieldRole, columnMetaDataForType, clr, true, null);
            if (NucleusLogger.DATASTORE.isInfoEnabled()) {
                NucleusLogger.DATASTORE.info(Localiser.msg("020188", implClass, mmd.getName()));
            }
        }
    }
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ArrayList(java.util.ArrayList) Iterator(java.util.Iterator) Collection(java.util.Collection) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) ColumnMetaData(org.datanucleus.metadata.ColumnMetaData) NoTableManagedException(org.datanucleus.store.rdbms.exceptions.NoTableManagedException)

Example 14 with DatastoreClass

use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.

the class FKListStore method validateElementForWriting.

/**
 * Method to validate that an element is valid for writing to the datastore.
 * TODO Minimise differences to super.validateElementForWriting()
 * @param op ObjectProvider for the List
 * @param element The element to validate
 * @param index The position that the element is being stored at in the list
 * @return Whether the element was inserted
 */
protected boolean validateElementForWriting(final ObjectProvider op, final Object element, final int index) {
    final Object newOwner = op.getObject();
    ComponentInfo info = getComponentInfoForElement(element);
    final DatastoreClass elementTable;
    if (storeMgr.getNucleusContext().getMetaDataManager().isPersistentInterface(elementType)) {
        elementTable = storeMgr.getDatastoreClass(storeMgr.getNucleusContext().getMetaDataManager().getImplementationNameForPersistentInterface(elementType), clr);
    } else {
        elementTable = storeMgr.getDatastoreClass(element.getClass().getName(), clr);
    }
    final JavaTypeMapping orderMapping;
    if (info != null) {
        orderMapping = info.getDatastoreClass().getExternalMapping(ownerMemberMetaData, MappingType.EXTERNAL_INDEX);
    } else {
        orderMapping = this.orderMapping;
    }
    // Check if element is ok for use in the datastore, specifying any external mappings that may be required
    boolean inserted = super.validateElementForWriting(op.getExecutionContext(), element, new FieldValues() {

        public void fetchFields(ObjectProvider elemOP) {
            // Find the (element) table storing the FK back to the owner
            if (elementTable != null) {
                JavaTypeMapping externalFKMapping = elementTable.getExternalMapping(ownerMemberMetaData, MappingType.EXTERNAL_FK);
                if (externalFKMapping != null) {
                    // The element has an external FK mapping so set the value it needs to use in the INSERT
                    elemOP.setAssociatedValue(externalFKMapping, op.getObject());
                }
                if (relationDiscriminatorMapping != null) {
                    elemOP.setAssociatedValue(relationDiscriminatorMapping, relationDiscriminatorValue);
                }
                if (orderMapping != null && index >= 0) {
                    if (ownerMemberMetaData.getOrderMetaData() != null && ownerMemberMetaData.getOrderMetaData().getMappedBy() != null) {
                        // Order is stored in a field in the element so update it
                        // We support mapped-by fields of types int/long/Integer/Long currently
                        Object indexValue = null;
                        if (orderMapping.getMemberMetaData().getTypeName().equals(ClassNameConstants.JAVA_LANG_LONG) || orderMapping.getMemberMetaData().getTypeName().equals(ClassNameConstants.LONG)) {
                            indexValue = Long.valueOf(index);
                        } else {
                            indexValue = Integer.valueOf(index);
                        }
                        elemOP.replaceFieldMakeDirty(orderMapping.getMemberMetaData().getAbsoluteFieldNumber(), indexValue);
                    } else {
                        // Order is stored in a surrogate column so save its vaue for the element to use later
                        elemOP.setAssociatedValue(orderMapping, Integer.valueOf(index));
                    }
                }
            }
            if (ownerMemberMetaData.getMappedBy() != null) {
                // TODO This is ManagedRelations - move into RelationshipManager
                // Managed Relations : 1-N bidir, so make sure owner is correct at persist
                // TODO Support DOT notation in mappedBy
                ObjectProvider ownerHolderOP = elemOP;
                int ownerFieldNumberInHolder = -1;
                if (ownerMemberMetaData.getMappedBy().indexOf('.') > 0) {
                    AbstractMemberMetaData otherMmd = null;
                    AbstractClassMetaData otherCmd = info.getAbstractClassMetaData();
                    String remainingMappedBy = ownerMemberMetaData.getMappedBy();
                    while (remainingMappedBy.indexOf('.') > 0) {
                        int dotPosition = remainingMappedBy.indexOf('.');
                        String thisMappedBy = remainingMappedBy.substring(0, dotPosition);
                        otherMmd = otherCmd.getMetaDataForMember(thisMappedBy);
                        Object holderValueAtField = ownerHolderOP.provideField(otherMmd.getAbsoluteFieldNumber());
                        ownerHolderOP = op.getExecutionContext().findObjectProviderForEmbedded(holderValueAtField, ownerHolderOP, otherMmd);
                        remainingMappedBy = remainingMappedBy.substring(dotPosition + 1);
                        otherCmd = storeMgr.getMetaDataManager().getMetaDataForClass(otherMmd.getTypeName(), clr);
                        if (remainingMappedBy.indexOf('.') < 0) {
                            otherMmd = otherCmd.getMetaDataForMember(remainingMappedBy);
                            ownerFieldNumberInHolder = otherMmd.getAbsoluteFieldNumber();
                        }
                    }
                } else {
                    ownerFieldNumberInHolder = info.getAbstractClassMetaData().getAbsolutePositionOfMember(ownerMemberMetaData.getMappedBy());
                }
                Object currentOwner = ownerHolderOP.provideField(ownerFieldNumberInHolder);
                if (currentOwner == null) {
                    // No owner, so correct it
                    NucleusLogger.PERSISTENCE.info(Localiser.msg("056037", op.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(ownerHolderOP.getObject())));
                    ownerHolderOP.replaceFieldMakeDirty(ownerFieldNumberInHolder, newOwner);
                } else if (currentOwner != newOwner && op.getReferencedPC() == null) {
                    // Inconsistent owner, so throw exception
                    throw new NucleusUserException(Localiser.msg("056038", op.getObjectAsPrintable(), ownerMemberMetaData.getFullFieldName(), StringUtils.toJVMIDString(ownerHolderOP.getObject()), StringUtils.toJVMIDString(currentOwner)));
                }
            }
        }

        public void fetchNonLoadedFields(ObjectProvider op) {
        }

        public FetchPlan getFetchPlanForLoading() {
            return null;
        }
    });
    return inserted;
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ObjectProvider(org.datanucleus.state.ObjectProvider) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) FieldValues(org.datanucleus.store.FieldValues) FetchPlan(org.datanucleus.FetchPlan) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData)

Example 15 with DatastoreClass

use of org.datanucleus.store.rdbms.table.DatastoreClass in project datanucleus-rdbms by datanucleus.

the class FKListStore 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 determing which fields of element to select
 * @param addRestrictionOnOwner Whether to restrict to a particular owner (otherwise functions as bulk fetch for many owners).
 * @param startIdx Start index for the iterator (or -1)
 * @param endIdx End index for the iterator (or -1)
 * @return The SQLStatement and its associated StatementClassMapping
 */
public IteratorStatement getIteratorStatement(ExecutionContext ec, FetchPlan fp, boolean addRestrictionOnOwner, int startIdx, int endIdx) {
    SelectStatement sqlStmt = null;
    StatementClassMapping stmtClassMapping = new StatementClassMapping();
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    if (elementInfo.length == 1 && elementInfo[0].getDatastoreClass().getDiscriminatorMetaData() != null && elementInfo[0].getDatastoreClass().getDiscriminatorMetaData().getStrategy() != DiscriminatorStrategy.NONE) {
        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;
        // Select the required fields
        SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, stmtClassMapping, fp, sqlStmt.getPrimaryTable(), elementCmd, fp.getMaxFetchDepth());
    } else {
        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);
            stmtClassMapping.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
            SelectStatement subStmt = stmtGen.getStatement(ec);
            // Select the required fields (of the element class)
            if (sqlStmt == null) {
                if (elementInfo.length > 1) {
                    SQLStatementHelper.selectIdentityOfCandidateInStatement(subStmt, stmtClassMapping, elementInfo[i].getAbstractClassMetaData());
                } else {
                    SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(subStmt, stmtClassMapping, fp, subStmt.getPrimaryTable(), elementInfo[i].getAbstractClassMetaData(), fp.getMaxFetchDepth());
                }
            } else {
                if (elementInfo.length > 1) {
                    SQLStatementHelper.selectIdentityOfCandidateInStatement(subStmt, null, elementInfo[i].getAbstractClassMetaData());
                } else {
                    SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(subStmt, null, fp, subStmt.getPrimaryTable(), elementInfo[i].getAbstractClassMetaData(), fp.getMaxFetchDepth());
                }
            }
            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 (indexedList) {
        // "Indexed List" so allow restriction on returned indexes
        boolean needsOrdering = true;
        if (startIdx == -1 && endIdx == -1) {
            // Just restrict to >= 0 so we don't get any disassociated elements
            SQLExpression indexExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
            SQLExpression indexVal = exprFactory.newLiteral(sqlStmt, orderMapping, 0);
            sqlStmt.whereAnd(indexExpr.ge(indexVal), true);
        } else if (startIdx >= 0 && endIdx == startIdx) {
            // Particular index required so add restriction
            needsOrdering = false;
            SQLExpression indexExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
            SQLExpression indexVal = exprFactory.newLiteral(sqlStmt, orderMapping, startIdx);
            sqlStmt.whereAnd(indexExpr.eq(indexVal), true);
        } else {
            // Add restrictions on start/end indices as required
            if (startIdx >= 0) {
                SQLExpression indexExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
                SQLExpression indexVal = exprFactory.newLiteral(sqlStmt, orderMapping, startIdx);
                sqlStmt.whereAnd(indexExpr.ge(indexVal), true);
            } else {
                // Just restrict to >= 0 so we don't get any disassociated elements
                SQLExpression indexExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
                SQLExpression indexVal = exprFactory.newLiteral(sqlStmt, orderMapping, 0);
                sqlStmt.whereAnd(indexExpr.ge(indexVal), true);
            }
            if (endIdx >= 0) {
                SQLExpression indexExpr2 = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
                SQLExpression indexVal2 = exprFactory.newLiteral(sqlStmt, orderMapping, endIdx);
                sqlStmt.whereAnd(indexExpr2.lt(indexVal2), true);
            }
        }
        if (needsOrdering) {
            // Order by the ordering column
            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);
        }
    } else {
        // Apply ordering defined by <order-by>
        DatastoreClass elementTbl = elementInfo[0].getDatastoreClass();
        FieldOrder[] orderComponents = ownerMemberMetaData.getOrderMetaData().getFieldOrders();
        SQLExpression[] orderExprs = new SQLExpression[orderComponents.length];
        boolean[] orderDirs = new boolean[orderComponents.length];
        for (int i = 0; i < orderComponents.length; i++) {
            String fieldName = orderComponents[i].getFieldName();
            JavaTypeMapping fieldMapping = elementTbl.getMemberMapping(elementInfo[0].getAbstractClassMetaData().getMetaDataForMember(fieldName));
            orderDirs[i] = !orderComponents[i].isForward();
            SQLTable fieldSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), fieldMapping);
            orderExprs[i] = exprFactory.newExpression(sqlStmt, fieldSqlTbl, fieldMapping);
        }
        sqlStmt.setOrdering(orderExprs, orderDirs);
    }
    return new IteratorStatement(this, sqlStmt, stmtClassMapping);
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) FieldOrder(org.datanucleus.metadata.OrderMetaData.FieldOrder) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) 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) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) NucleusException(org.datanucleus.exceptions.NucleusException)

Aggregations

DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)87 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)60 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)49 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)48 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)44 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)41 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)35 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)32 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)28 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)26 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)21 MapTable (org.datanucleus.store.rdbms.table.MapTable)19 NucleusException (org.datanucleus.exceptions.NucleusException)18 SecondaryDatastoreClass (org.datanucleus.store.rdbms.table.SecondaryDatastoreClass)15 ArrayList (java.util.ArrayList)14 ExecutionContext (org.datanucleus.ExecutionContext)13 JoinTable (org.datanucleus.store.rdbms.table.JoinTable)13 Table (org.datanucleus.store.rdbms.table.Table)13 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)11 UnboundExpression (org.datanucleus.store.rdbms.sql.expression.UnboundExpression)11