Search in sources :

Example 11 with DiscriminatorMetaData

use of org.datanucleus.metadata.DiscriminatorMetaData in project datanucleus-api-jdo by datanucleus.

the class InheritanceMetadataImpl method newDiscriminatorMetadata.

/* (non-Javadoc)
     * @see javax.jdo.metadata.InheritanceMetadata#newDiscriminatorMetadata()
     */
public DiscriminatorMetadata newDiscriminatorMetadata() {
    DiscriminatorMetaData internalDismd = getInternal().newDiscriminatorMetadata();
    DiscriminatorMetadataImpl dismd = new DiscriminatorMetadataImpl(internalDismd);
    dismd.parent = this;
    return dismd;
}
Also used : DiscriminatorMetaData(org.datanucleus.metadata.DiscriminatorMetaData)

Example 12 with DiscriminatorMetaData

use of org.datanucleus.metadata.DiscriminatorMetaData in project datanucleus-rdbms by datanucleus.

the class RDBMSStoreHelper method getClassNameForIdUsingDiscriminator.

/**
 * Utility that does a discriminator candidate query for the specified candidate and subclasses
 * and returns the class name of the instance that has the specified identity (if any).
 * @param storeMgr RDBMS StoreManager
 * @param ec execution context
 * @param id The id
 * @param cmd Metadata for the root candidate class
 * @return Name of the class with this identity (or null if none found)
 */
public static String getClassNameForIdUsingDiscriminator(RDBMSStoreManager storeMgr, ExecutionContext ec, Object id, AbstractClassMetaData cmd) {
    // Check for input error
    if (cmd == null || id == null) {
        return null;
    }
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    DatastoreClass primaryTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr);
    // Form the query to find which one of these classes has the instance with this id
    DiscriminatorStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, clr.classForName(cmd.getFullClassName()), true, null, null);
    stmtGen.setOption(SelectStatementGenerator.OPTION_RESTRICT_DISCRIM);
    SelectStatement sqlStmt = stmtGen.getStatement(ec);
    // Select the discriminator
    JavaTypeMapping discrimMapping = primaryTable.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
    SQLTable discrimSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), discrimMapping);
    sqlStmt.select(discrimSqlTbl, discrimMapping, null);
    // Restrict to this id
    JavaTypeMapping idMapping = primaryTable.getIdMapping();
    JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
    SQLExpression sqlFldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
    SQLExpression sqlFldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
    sqlStmt.whereAnd(sqlFldExpr.eq(sqlFldVal), true);
    // Perform the query
    try {
        ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
        SQLController sqlControl = storeMgr.getSQLController();
        if (ec.getSerializeReadForClass(cmd.getFullClassName())) {
            sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
        }
        try {
            PreparedStatement ps = SQLStatementHelper.getPreparedStatementForSQLStatement(sqlStmt, ec, mconn, null, null);
            String statement = sqlStmt.getSQLText().toSQL();
            try {
                ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps);
                try {
                    while (rs.next()) {
                        DiscriminatorMetaData dismd = discrimMapping.getTable().getDiscriminatorMetaData();
                        return RDBMSQueryUtils.getClassNameFromDiscriminatorResultSetRow(discrimMapping, dismd, rs, ec);
                    }
                } finally {
                    rs.close();
                }
            } finally {
                sqlControl.closeStatement(mconn, ps);
            }
        } finally {
            mconn.release();
        }
    } catch (SQLException sqe) {
        NucleusLogger.DATASTORE.error("Exception thrown on querying of discriminator for id", sqe);
        throw new NucleusDataStoreException(sqe.toString(), sqe);
    }
    return null;
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SQLException(java.sql.SQLException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) PreparedStatement(java.sql.PreparedStatement) PersistableIdMapping(org.datanucleus.store.rdbms.mapping.java.PersistableIdMapping) DiscriminatorMetaData(org.datanucleus.metadata.DiscriminatorMetaData) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) DiscriminatorStatementGenerator(org.datanucleus.store.rdbms.sql.DiscriminatorStatementGenerator) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass)

Example 13 with DiscriminatorMetaData

use of org.datanucleus.metadata.DiscriminatorMetaData in project datanucleus-rdbms by datanucleus.

the class UnionStatementGenerator method getSelectStatementForCandidate.

/**
 * Convenience method to return the SelectStatement for a particular class.
 * Returns a SelectStatement with primaryTable of the "candidateTable", and which joins to the table of the class (if different).
 * @param className The class name to generate the statement for
 * @param ec ExecutionContext
 * @return The SelectStatement
 */
protected SelectStatement getSelectStatementForCandidate(String className, ExecutionContext ec) {
    DatastoreClass table = storeMgr.getDatastoreClass(className, clr);
    if (table == null) {
        // Subclass-table, so persisted into table(s) of subclasses
        NucleusLogger.GENERAL.info("Generation of statement to retrieve objects of type " + candidateType.getName() + (includeSubclasses ? " including subclasses " : "") + " attempted to include " + className + " but this has no table of its own; ignored");
        // TODO Cater for use of single subclass-table
        return null;
    }
    // Start from an SQL SELECT of the candidate table
    SelectStatement stmt = new SelectStatement(parentStmt, storeMgr, candidateTable, candidateTableAlias, candidateTableGroupName);
    stmt.setClassLoaderResolver(clr);
    stmt.setCandidateClassName(className);
    String tblGroupName = stmt.getPrimaryTable().getGroupName();
    if (table != candidateTable) {
        // INNER JOIN from the root candidate table to this candidates table
        JavaTypeMapping candidateIdMapping = candidateTable.getIdMapping();
        JavaTypeMapping tableIdMapping = table.getIdMapping();
        SQLTable tableSqlTbl = stmt.join(JoinType.INNER_JOIN, null, candidateIdMapping, table, null, tableIdMapping, null, stmt.getPrimaryTable().getGroupName(), true);
        tblGroupName = tableSqlTbl.getGroupName();
    }
    // Add any discriminator restriction in this table for the specified class
    // Caters for the case where we have more than 1 class stored in this table
    SQLExpressionFactory factory = storeMgr.getSQLExpressionFactory();
    JavaTypeMapping discriminatorMapping = table.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, false);
    DiscriminatorMetaData discriminatorMetaData = table.getDiscriminatorMetaData();
    if (discriminatorMapping != null && discriminatorMetaData.getStrategy() != DiscriminatorStrategy.NONE) {
        // Restrict to valid discriminator values where we have a discriminator specified on this table
        AbstractClassMetaData targetCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(className, clr);
        SQLExpression discExpr = factory.newExpression(stmt, stmt.getPrimaryTable(), discriminatorMapping);
        SQLExpression discValExpr = factory.newLiteral(stmt, discriminatorMapping, targetCmd.getDiscriminatorValue());
        stmt.whereAnd(discExpr.eq(discValExpr), false);
    }
    JavaTypeMapping multitenancyMapping = table.getSurrogateMapping(SurrogateColumnType.MULTITENANCY, false);
    if (multitenancyMapping != null) {
        // Multi-tenancy restriction
        AbstractClassMetaData cmd = table.getClassMetaData();
        SQLTable tenantSqlTbl = stmt.getTable(multitenancyMapping.getTable(), tblGroupName);
        SQLExpression tenantExpr = stmt.getSQLExpressionFactory().newExpression(stmt, tenantSqlTbl, multitenancyMapping);
        SQLExpression tenantVal = stmt.getSQLExpressionFactory().newLiteral(stmt, multitenancyMapping, ec.getNucleusContext().getMultiTenancyId(ec, cmd));
        stmt.whereAnd(tenantExpr.eq(tenantVal), true);
    }
    JavaTypeMapping softDeleteMapping = table.getSurrogateMapping(SurrogateColumnType.SOFTDELETE, false);
    if (softDeleteMapping != null && !hasOption(OPTION_INCLUDE_SOFT_DELETES)) {
        // Soft-delete restriction
        SQLTable softDeleteSqlTbl = stmt.getTable(softDeleteMapping.getTable(), tblGroupName);
        SQLExpression softDeleteExpr = stmt.getSQLExpressionFactory().newExpression(stmt, softDeleteSqlTbl, softDeleteMapping);
        SQLExpression softDeleteVal = stmt.getSQLExpressionFactory().newLiteral(stmt, softDeleteMapping, Boolean.FALSE);
        stmt.whereAnd(softDeleteExpr.eq(softDeleteVal), true);
    }
    // Eliminate any subclasses (catered for in separate UNION statement)
    Iterator<String> subIter = storeMgr.getSubClassesForClass(className, false, clr).iterator();
    while (subIter.hasNext()) {
        String subclassName = subIter.next();
        DatastoreClass[] subclassTables = null;
        DatastoreClass subclassTable = storeMgr.getDatastoreClass(subclassName, clr);
        if (subclassTable == null) {
            AbstractClassMetaData targetSubCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(subclassName, clr);
            AbstractClassMetaData[] targetSubCmds = storeMgr.getClassesManagingTableForClass(targetSubCmd, clr);
            subclassTables = new DatastoreClass[targetSubCmds.length];
            for (int i = 0; i < targetSubCmds.length; i++) {
                subclassTables[i] = storeMgr.getDatastoreClass(targetSubCmds[i].getFullClassName(), clr);
            }
        } else {
            subclassTables = new DatastoreClass[1];
            subclassTables[0] = subclassTable;
        }
        for (int i = 0; i < subclassTables.length; i++) {
            if (subclassTables[i] != table) {
                // Subclass of our class is stored in different table to the candidate so exclude it
                // Adds FROM clause of "LEFT OUTER JOIN {subTable} ON ..."
                // and WHERE clause of "{subTable}.ID = NULL"
                JavaTypeMapping tableIdMapping = table.getIdMapping();
                JavaTypeMapping subclassIdMapping = subclassTables[i].getIdMapping();
                SQLTable sqlTableSubclass = stmt.join(JoinType.LEFT_OUTER_JOIN, null, tableIdMapping, subclassTables[i], null, subclassIdMapping, null, stmt.getPrimaryTable().getGroupName(), true);
                SQLExpression subclassIdExpr = factory.newExpression(stmt, sqlTableSubclass, subclassIdMapping);
                SQLExpression nullExpr = new NullLiteral(stmt, null, null, null);
                stmt.whereAnd(subclassIdExpr.eq(nullExpr), false);
            }
        }
    }
    if (hasOption(OPTION_SELECT_DN_TYPE)) {
        // Add SELECT of dummy metadata for this class ("'mydomain.MyClass' AS DN_TYPE")
        addTypeSelectForClass(stmt, className);
    }
    return stmt;
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) DiscriminatorMetaData(org.datanucleus.metadata.DiscriminatorMetaData) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) NullLiteral(org.datanucleus.store.rdbms.sql.expression.NullLiteral)

Example 14 with DiscriminatorMetaData

use of org.datanucleus.metadata.DiscriminatorMetaData in project datanucleus-rdbms by datanucleus.

the class UnionStatementGenerator method getSQLStatementForCandidateViaJoin.

/**
 * Convenience method to return the SQLStatement for a particular class selecting a join table.
 * Returns a SQLStatement with primaryTable of the "joinTable", and which joins to the table of the class.
 * @param className The class name to generate the statement for
 * @return The SQLStatement
 */
protected SelectStatement getSQLStatementForCandidateViaJoin(String className) {
    DatastoreClass table = storeMgr.getDatastoreClass(className, clr);
    if (table == null) {
        // TODO Cater for use of single subclass-table
        throw new NucleusException("We do not currently support a UNION statement for class=" + className + " since it has no table of its own");
    }
    // Start from an SQL SELECT of the join table
    SelectStatement stmt = new SelectStatement(parentStmt, storeMgr, joinTable, joinTableAlias, candidateTableGroupName);
    stmt.setClassLoaderResolver(clr);
    stmt.setCandidateClassName(className);
    // INNER/LEFT OUTER JOIN from the join table to the root candidate table
    // If we allow nulls we do a left outer join here, otherwise an inner join
    SQLTable candidateSQLTable = null;
    if (candidateTable != null) {
        // We have a root candidate table, so join to that
        JavaTypeMapping candidateIdMapping = candidateTable.getIdMapping();
        if (hasOption(OPTION_ALLOW_NULLS)) {
            // Put element table in same table group since all relates to the elements
            candidateSQLTable = stmt.join(JoinType.LEFT_OUTER_JOIN, null, joinElementMapping, candidateTable, null, candidateIdMapping, null, stmt.getPrimaryTable().getGroupName(), true);
        } else {
            // Put element table in same table group since all relates to the elements
            candidateSQLTable = stmt.join(JoinType.INNER_JOIN, null, joinElementMapping, candidateTable, null, candidateIdMapping, null, stmt.getPrimaryTable().getGroupName(), true);
        }
        // Join the root candidate table to this particular candidate table
        if (table != candidateTable) {
            // INNER JOIN from the root candidate table to this candidates table
            stmt.join(JoinType.INNER_JOIN, candidateSQLTable, candidateIdMapping, table, null, table.getIdMapping(), null, stmt.getPrimaryTable().getGroupName(), true);
        }
    } else {
        // No root candidate table, so join direct to this candidate
        JavaTypeMapping candidateIdMapping = table.getIdMapping();
        if (hasOption(OPTION_ALLOW_NULLS)) {
            // Put element table in same table group since all relates to the elements
            candidateSQLTable = stmt.join(JoinType.LEFT_OUTER_JOIN, null, joinElementMapping, table, null, candidateIdMapping, null, stmt.getPrimaryTable().getGroupName(), true);
        } else {
            // Put element table in same table group since all relates to the elements
            candidateSQLTable = stmt.join(JoinType.INNER_JOIN, null, joinElementMapping, table, null, candidateIdMapping, null, stmt.getPrimaryTable().getGroupName(), true);
        }
    }
    // Add any discriminator restriction in the table for the specified class
    // Caters for the case where we have more than 1 class stored in this table
    SQLExpressionFactory factory = storeMgr.getSQLExpressionFactory();
    JavaTypeMapping discriminatorMapping = table.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, false);
    DiscriminatorMetaData discriminatorMetaData = table.getDiscriminatorMetaData();
    if (discriminatorMapping != null && discriminatorMetaData.getStrategy() != DiscriminatorStrategy.NONE) {
        // Restrict to valid discriminator value where we have a discriminator specified on this table
        BooleanExpression discExpr = SQLStatementHelper.getExpressionForDiscriminatorForClass(stmt, className, discriminatorMetaData, discriminatorMapping, stmt.getPrimaryTable(), clr);
        stmt.whereAnd(discExpr, false);
    }
    // Eliminate any subclasses (catered for in separate UNION statement)
    Iterator<String> subIter = storeMgr.getSubClassesForClass(className, false, clr).iterator();
    while (subIter.hasNext()) {
        String subclassName = subIter.next();
        DatastoreClass[] subclassTables = null;
        DatastoreClass subclassTable = storeMgr.getDatastoreClass(subclassName, clr);
        if (subclassTable == null) {
            AbstractClassMetaData targetSubCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(subclassName, clr);
            AbstractClassMetaData[] targetSubCmds = storeMgr.getClassesManagingTableForClass(targetSubCmd, clr);
            subclassTables = new DatastoreClass[targetSubCmds.length];
            for (int i = 0; i < targetSubCmds.length; i++) {
                subclassTables[i] = storeMgr.getDatastoreClass(targetSubCmds[i].getFullClassName(), clr);
            }
        } else {
            subclassTables = new DatastoreClass[1];
            subclassTables[0] = subclassTable;
        }
        for (int i = 0; i < subclassTables.length; i++) {
            if (subclassTables[i] != table) {
                // Subclass of our class is stored in different table to the candidate so exclude it
                // Adds FROM clause of "LEFT OUTER JOIN {subTable} ON ..."
                // and WHERE clause of "{subTable}.ID = NULL"
                JavaTypeMapping subclassIdMapping = subclassTables[i].getIdMapping();
                SQLTable sqlTableSubclass = stmt.join(JoinType.LEFT_OUTER_JOIN, null, joinElementMapping, subclassTables[i], null, subclassIdMapping, null, stmt.getPrimaryTable().getGroupName(), true);
                SQLExpression subclassIdExpr = factory.newExpression(stmt, sqlTableSubclass, subclassIdMapping);
                SQLExpression nullExpr = new NullLiteral(stmt, null, null, null);
                stmt.whereAnd(subclassIdExpr.eq(nullExpr), false);
            }
        }
    }
    if (hasOption(OPTION_SELECT_DN_TYPE)) {
        // Add SELECT of dummy metadata for this class ("'mydomain.MyClass' AS DN_TYPE")
        addTypeSelectForClass(stmt, className);
    }
    return stmt;
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) DiscriminatorMetaData(org.datanucleus.metadata.DiscriminatorMetaData) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) NucleusException(org.datanucleus.exceptions.NucleusException) NullLiteral(org.datanucleus.store.rdbms.sql.expression.NullLiteral)

Example 15 with DiscriminatorMetaData

use of org.datanucleus.metadata.DiscriminatorMetaData in project datanucleus-rdbms by datanucleus.

the class PersistentClassROF method getObject.

/**
 * Method to convert the current ResultSet row into a persistable Object.
 * @return The persistable object.
 */
public T getObject() {
    // Find the class of the returned object in this row of the ResultSet
    String className = null;
    boolean requiresInheritanceCheck = true;
    StatementMappingIndex discrimMapIdx = resultMapping.getMappingForMemberPosition(SurrogateColumnType.DISCRIMINATOR.getFieldNumber());
    if (discrimMapIdx != null) {
        // Discriminator mapping registered so use that
        try {
            String discrimValue = rs.getString(discrimMapIdx.getColumnPositions()[0]);
            if (discrimValue == null) {
                // Discriminator has no value so return null object
                NucleusLogger.DATASTORE_RETRIEVE.debug("Value of discriminator is null so assuming object is null");
                return null;
            }
            JavaTypeMapping discrimMapping = discrimMapIdx.getMapping();
            DiscriminatorMetaData dismd = (discrimMapping != null ? discrimMapping.getTable().getDiscriminatorMetaData() : null);
            className = ec.getMetaDataManager().getClassNameFromDiscriminatorValue(discrimValue, dismd);
            requiresInheritanceCheck = false;
        } catch (SQLException sqle) {
            NucleusLogger.DATASTORE_RETRIEVE.debug("Exception obtaining value of discriminator : " + sqle.getMessage());
        }
    } else if (resultMapping.getNucleusTypeColumnName() != null) {
        // Extract the object type using the NucleusType column (if available)
        try {
            className = rs.getString(resultMapping.getNucleusTypeColumnName());
            if (className == null) {
                // Discriminator has no value so return null object
                NucleusLogger.DATASTORE_RETRIEVE.debug("Value of determiner column is null so assuming object is null");
                return null;
            }
            className = className.trim();
            requiresInheritanceCheck = false;
        } catch (SQLException sqle) {
        // NucleusType column not found so ignore
        }
    }
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    Class pcClassForObject = persistentClass;
    if (className != null) {
        Class cls = (Class) resolvedClasses.get(className);
        if (cls != null) {
            pcClassForObject = cls;
        } else {
            if (persistentClass.getName().equals(className)) {
                pcClassForObject = persistentClass;
            } else {
                pcClassForObject = clr.classForName(className, persistentClass.getClassLoader());
            }
            resolvedClasses.put(className, pcClassForObject);
        }
    }
    if (requiresInheritanceCheck) {
        // Check if no instantiable subclasses
        String[] subclasses = ec.getMetaDataManager().getSubclassesForClass(pcClassForObject.getName(), false);
        if (subclasses == null || subclasses.length == 0) {
            requiresInheritanceCheck = false;
        }
    }
    String warnMsg = null;
    if (Modifier.isAbstract(pcClassForObject.getModifiers())) {
        // Persistent class is abstract so we can't create instances of that type!
        // This can happen if the user is using subclass-table and hasn't provided a discriminator in
        // the table. Try going out one level and find a (single) concrete subclass
        // TODO make this more robust and go out further
        String[] subclasses = ec.getMetaDataManager().getSubclassesForClass(pcClassForObject.getName(), false);
        if (subclasses != null) {
            Class concreteSubclass = null;
            int numConcreteSubclasses = 0;
            for (int i = 0; i < subclasses.length; i++) {
                Class subcls = clr.classForName(subclasses[i]);
                if (!Modifier.isAbstract(subcls.getModifiers())) {
                    numConcreteSubclasses++;
                    concreteSubclass = subcls;
                }
            }
            if (numConcreteSubclasses == 1) {
                // Only one possible subclass, so use that
                NucleusLogger.DATASTORE_RETRIEVE.warn(Localiser.msg("052300", pcClassForObject.getName(), concreteSubclass.getName()));
                pcClassForObject = concreteSubclass;
            } else if (numConcreteSubclasses == 0) {
                throw new NucleusUserException(Localiser.msg("052301", pcClassForObject.getName()));
            } else {
                // More than 1 possible so notify the user. Really should return the abstract
                warnMsg = "Found type=" + pcClassForObject + " but abstract and more than 1 concrete subclass (" + StringUtils.objectArrayToString(subclasses) + "). Really you need a discriminator to help identifying the type. Choosing " + concreteSubclass;
                pcClassForObject = concreteSubclass;
                requiresInheritanceCheck = true;
            }
        }
    }
    // Find the statement mappings and field numbers to use for the result class
    // Caters for persistent-interfaces and the result class being an implementation
    AbstractClassMetaData cmd = ec.getMetaDataManager().getMetaDataForClass(pcClassForObject, clr);
    if (cmd == null) {
        // TODO Improve this and check PK cols
        return null;
    }
    int[] fieldNumbers = resultMapping.getMemberNumbers();
    // TODO We need this on the first object only to generate the ResultSetGetter; can we optimise this?
    StatementClassMapping mappingDefinition;
    int[] mappedFieldNumbers;
    if (rootCmd instanceof InterfaceMetaData) {
        // Persistent-interface : create new mapping definition for a result type of the implementation
        mappingDefinition = new StatementClassMapping();
        mappingDefinition.setNucleusTypeColumnName(resultMapping.getNucleusTypeColumnName());
        mappedFieldNumbers = new int[fieldNumbers.length];
        for (int i = 0; i < fieldNumbers.length; i++) {
            AbstractMemberMetaData mmd = rootCmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumbers[i]);
            mappedFieldNumbers[i] = cmd.getAbsolutePositionOfMember(mmd.getName());
            mappingDefinition.addMappingForMember(mappedFieldNumbers[i], resultMapping.getMappingForMemberPosition(fieldNumbers[i]));
        }
    } else {
        // Persistent class
        mappingDefinition = resultMapping;
        mappedFieldNumbers = fieldNumbers;
    }
    if (resultSetGetter == null) {
        // Use this result mapping definition for our ResultSetGetter
        this.resultSetGetter = new ResultSetGetter(ec, rs, mappingDefinition, rootCmd);
    }
    // Extract any surrogate version
    VersionMetaData vermd = cmd.getVersionMetaDataForClass();
    Object surrogateVersion = null;
    StatementMappingIndex versionMapping = null;
    if (vermd != null) {
        if (vermd.getFieldName() == null) {
            versionMapping = resultMapping.getMappingForMemberPosition(SurrogateColumnType.VERSION.getFieldNumber());
        } else {
            AbstractMemberMetaData vermmd = cmd.getMetaDataForMember(vermd.getFieldName());
            versionMapping = resultMapping.getMappingForMemberPosition(vermmd.getAbsoluteFieldNumber());
        }
    }
    if (versionMapping != null) {
        // Surrogate version column returned by query
        JavaTypeMapping mapping = versionMapping.getMapping();
        surrogateVersion = mapping.getObject(ec, rs, versionMapping.getColumnPositions());
    }
    // Extract the object from the ResultSet
    T obj = null;
    boolean needToSetVersion = false;
    if (persistentClass.isInterface() && !cmd.isImplementationOfPersistentDefinition()) {
        // Querying by interface, and not a generated implementation so use the metadata for the interface
        cmd = ec.getMetaDataManager().getMetaDataForInterface(persistentClass, clr);
        if (cmd == null) {
            // Fallback to the value we had
            cmd = ec.getMetaDataManager().getMetaDataForClass(pcClassForObject, clr);
        }
    }
    if (cmd.getIdentityType() == IdentityType.APPLICATION) {
        // Check if the PK field(s) are all null (implies null object, when using OUTER JOIN)
        int[] pkNumbers = cmd.getPKMemberPositions();
        boolean nullObject = true;
        for (int i = 0; i < pkNumbers.length; i++) {
            StatementMappingIndex pkIdx = mappingDefinition.getMappingForMemberPosition(pkNumbers[i]);
            if (pkIdx == null) {
                throw new NucleusException("You have just executed an SQL statement yet the information " + "for the primary key column(s) is not available! Please generate a testcase and report this issue");
            }
            int[] colPositions = pkIdx.getColumnPositions();
            for (int j = 0; j < colPositions.length; j++) {
                try {
                    Object pkObj = rs.getObject(colPositions[j]);
                    if (pkObj != null) {
                        nullObject = false;
                        break;
                    }
                } catch (SQLException sqle) {
                    NucleusLogger.DATASTORE_RETRIEVE.warn("Exception thrown while retrieving results ", sqle);
                }
                if (!nullObject) {
                    break;
                }
            }
        }
        if (!nullObject) {
            // Retrieve the object with this application-identity
            if (warnMsg != null) {
                NucleusLogger.DATASTORE_RETRIEVE.warn(warnMsg);
            }
            Object id = IdentityUtils.getApplicationIdentityForResultSetRow(ec, cmd, pcClassForObject, requiresInheritanceCheck, resultSetGetter);
            String idClassName = IdentityUtils.getTargetClassNameForIdentity(id);
            if (idClassName != null) {
                // "identity" defines the class name
                pcClassForObject = clr.classForName(idClassName);
            }
            obj = findObjectWithIdAndLoadFields(id, mappedFieldNumbers, pcClassForObject, cmd, surrogateVersion);
        }
    } else if (cmd.getIdentityType() == IdentityType.DATASTORE) {
        // Generate the "id" for this object (of type pcClassForObject), and find the object for that
        StatementMappingIndex datastoreIdMapping = resultMapping.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
        JavaTypeMapping mapping = datastoreIdMapping.getMapping();
        Object id = mapping.getObject(ec, rs, datastoreIdMapping.getColumnPositions());
        if (id != null) {
            String idClassName = IdentityUtils.getTargetClassNameForIdentity(id);
            if (!pcClassForObject.getName().equals(idClassName)) {
                // Get a DatastoreId for the right inheritance level
                id = ec.getNucleusContext().getIdentityManager().getDatastoreId(pcClassForObject.getName(), IdentityUtils.getTargetKeyForDatastoreIdentity(id));
            }
            if (warnMsg != null) {
                NucleusLogger.DATASTORE_RETRIEVE.warn(warnMsg);
            }
            if (mappedFieldNumbers == null) {
                obj = (T) ec.findObject(id, false, requiresInheritanceCheck, null);
                needToSetVersion = true;
            } else {
                obj = findObjectWithIdAndLoadFields(id, mappedFieldNumbers, requiresInheritanceCheck ? null : pcClassForObject, cmd, surrogateVersion);
            }
        }
    } else if (cmd.getIdentityType() == IdentityType.NONDURABLE) {
        String classNameForId = className;
        if (className == null) {
            // No discriminator info from the query, so just fallback to default type
            classNameForId = cmd.getFullClassName();
        }
        Object id = ec.newObjectId(classNameForId, null);
        if (mappedFieldNumbers == null) {
            obj = (T) ec.findObject(id, false, requiresInheritanceCheck, null);
            needToSetVersion = true;
        } else {
            obj = findObjectWithIdAndLoadFields(id, fieldNumbers, pcClassForObject, cmd, surrogateVersion);
        }
    }
    if (obj != null && needToSetVersion) {
        // Set the version of the object where possible
        if (surrogateVersion != null) {
            ObjectProvider objOP = ec.findObjectProvider(obj);
            objOP.setVersion(surrogateVersion);
        } else {
            if (vermd != null && vermd.getFieldName() != null) {
                // Version stored in a normal field
                int versionFieldNumber = rootCmd.getMetaDataForMember(vermd.getFieldName()).getAbsoluteFieldNumber();
                if (resultMapping.getMappingForMemberPosition(versionFieldNumber) != null) {
                    ObjectProvider objOP = ec.findObjectProvider(obj);
                    Object verFieldValue = objOP.provideField(versionFieldNumber);
                    if (verFieldValue != null) {
                        objOP.setVersion(verFieldValue);
                    }
                }
            }
        }
    }
    return obj;
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SQLException(java.sql.SQLException) VersionMetaData(org.datanucleus.metadata.VersionMetaData) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ResultSetGetter(org.datanucleus.store.rdbms.fieldmanager.ResultSetGetter) DiscriminatorMetaData(org.datanucleus.metadata.DiscriminatorMetaData) InterfaceMetaData(org.datanucleus.metadata.InterfaceMetaData) ObjectProvider(org.datanucleus.state.ObjectProvider) NucleusException(org.datanucleus.exceptions.NucleusException) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

DiscriminatorMetaData (org.datanucleus.metadata.DiscriminatorMetaData)18 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)11 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)7 NucleusException (org.datanucleus.exceptions.NucleusException)5 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)5 ColumnMetaData (org.datanucleus.metadata.ColumnMetaData)5 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)4 IndexMetaData (org.datanucleus.metadata.IndexMetaData)4 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)3 ForeignKeyMetaData (org.datanucleus.metadata.ForeignKeyMetaData)3 InheritanceMetaData (org.datanucleus.metadata.InheritanceMetaData)3 InterfaceMetaData (org.datanucleus.metadata.InterfaceMetaData)3 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)3 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)3 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)3 SQLException (java.sql.SQLException)2 HashMap (java.util.HashMap)2 Iterator (java.util.Iterator)2 Map (java.util.Map)2 AttributeConverter (javax.jdo.AttributeConverter)2