Search in sources :

Example 6 with ReferenceMapping

use of org.datanucleus.store.rdbms.mapping.java.ReferenceMapping in project datanucleus-rdbms by datanucleus.

the class ObjectExpression method is.

/**
 * An "is" (instanceOf) expression, providing a BooleanExpression whether this expression is an instanceof the provided type.
 * @param expr The expression representing the type
 * @param not Whether the operator is "!instanceof"
 * @return Whether this expression is an instance of the provided type
 */
public BooleanExpression is(SQLExpression expr, boolean not) {
    RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
    ClassLoaderResolver clr = stmt.getClassLoaderResolver();
    // Extract instanceOf type
    String instanceofClassName = null;
    SQLExpression classExpr = expr;
    if (expr instanceof TypeConverterLiteral) {
        // For some reason the user has input "TYPE(field) = :param" and param is a type-converted value
        classExpr = ((TypeConverterLiteral) expr).getDelegate();
    }
    if (classExpr instanceof StringLiteral) {
        instanceofClassName = (String) ((StringLiteral) classExpr).getValue();
    } else if (classExpr instanceof CollectionLiteral) {
        // "a instanceof (b1,b2,b3)"
        CollectionLiteral typesLiteral = (CollectionLiteral) classExpr;
        Collection values = (Collection) typesLiteral.getValue();
        if (values.size() == 1) {
            Object value = values.iterator().next();
            String valueStr = null;
            if (value instanceof Class) {
                valueStr = ((Class) value).getCanonicalName();
            } else if (value instanceof String) {
                valueStr = (String) value;
            } else {
                throw new NucleusUserException("Do not support CollectionLiteral of element type " + value.getClass().getName());
            }
            return is(new StringLiteral(stmt, typesLiteral.getJavaTypeMapping(), valueStr, typesLiteral.getParameterName()), not);
        }
        List<BooleanExpression> listExp = new LinkedList<>();
        for (Object value : values) {
            String valueStr = null;
            if (value instanceof Class) {
                valueStr = ((Class) value).getCanonicalName();
            } else if (value instanceof String) {
                valueStr = (String) value;
            } else {
                throw new NucleusUserException("Do not support CollectionLiteral of element type " + value.getClass().getName());
            }
            listExp.add(is(new StringLiteral(stmt, typesLiteral.getJavaTypeMapping(), valueStr, typesLiteral.getParameterName()), false));
        }
        BooleanExpression result = null;
        for (BooleanExpression sqlExpression : listExp) {
            result = result == null ? sqlExpression : result.ior(sqlExpression);
        }
        if (result != null) {
            return not ? result.not() : result;
        }
    } else {
        throw new NucleusUserException("Do not currently support `instanceof` with class expression of type " + classExpr);
    }
    Class type = null;
    try {
        type = stmt.getQueryGenerator().resolveClass(instanceofClassName);
    } catch (ClassNotResolvedException cnre) {
        type = null;
    }
    if (type == null) {
        throw new NucleusUserException(Localiser.msg("037016", instanceofClassName));
    }
    // Extract type of member and check obvious conditions
    SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
    Class memberType = clr.classForName(mapping.getType());
    if (!memberType.isAssignableFrom(type) && !type.isAssignableFrom(memberType)) {
        // Member type and instanceof type are totally incompatible, so just return false
        JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
        return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, not));
    } else if (memberType == type) {
        // instanceof type is the same as the member type therefore must comply (can't store supertypes)
        JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
        return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, !not));
    }
    if (mapping instanceof EmbeddedMapping) {
        // Don't support embedded instanceof expressions
        AbstractClassMetaData fieldCmd = storeMgr.getMetaDataManager().getMetaDataForClass(mapping.getType(), clr);
        if (fieldCmd.hasDiscriminatorStrategy()) {
            // Embedded field with inheritance so add discriminator restriction
            JavaTypeMapping discMapping = ((EmbeddedMapping) mapping).getDiscriminatorMapping();
            AbstractClassMetaData typeCmd = storeMgr.getMetaDataManager().getMetaDataForClass(type, clr);
            SQLExpression discExpr = stmt.getSQLExpressionFactory().newExpression(stmt, table, discMapping);
            SQLExpression discValExpr = stmt.getSQLExpressionFactory().newLiteral(stmt, discMapping, typeCmd.getDiscriminatorValue());
            BooleanExpression typeExpr = (not ? discExpr.ne(discValExpr) : discExpr.eq(discValExpr));
            Iterator<String> subclassIter = storeMgr.getSubClassesForClass(type.getName(), true, clr).iterator();
            while (subclassIter.hasNext()) {
                String subclassName = subclassIter.next();
                AbstractClassMetaData subtypeCmd = storeMgr.getMetaDataManager().getMetaDataForClass(subclassName, clr);
                Object subtypeDiscVal = subtypeCmd.getDiscriminatorValue();
                discValExpr = stmt.getSQLExpressionFactory().newLiteral(stmt, discMapping, subtypeDiscVal);
                BooleanExpression subtypeExpr = (not ? discExpr.ne(discValExpr) : discExpr.eq(discValExpr));
                if (not) {
                    typeExpr = typeExpr.and(subtypeExpr);
                } else {
                    typeExpr = typeExpr.ior(subtypeExpr);
                }
            }
            return typeExpr;
        }
        JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
        return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, not));
    } else if (mapping instanceof PersistableMapping || mapping instanceof ReferenceMapping) {
        // Field has its own table, so join to it
        AbstractClassMetaData memberCmd = storeMgr.getMetaDataManager().getMetaDataForClass(mapping.getType(), clr);
        DatastoreClass memberTable = null;
        if (memberCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUBCLASS_TABLE) {
            // Field is a PC class that uses "subclass-table" inheritance strategy (and so has multiple possible tables to join to)
            AbstractClassMetaData[] cmds = storeMgr.getClassesManagingTableForClass(memberCmd, clr);
            if (cmds != null) {
                // TODO Allow for all possible tables. Can we do an OR of the tables ? How ?
                if (cmds.length > 1) {
                    NucleusLogger.QUERY.warn(Localiser.msg("037006", mapping.getMemberMetaData().getFullFieldName(), cmds[0].getFullClassName()));
                }
                memberTable = storeMgr.getDatastoreClass(cmds[0].getFullClassName(), clr);
            } else {
                // No subclasses with tables to join to, so throw a user error
                throw new NucleusUserException(Localiser.msg("037005", mapping.getMemberMetaData().getFullFieldName()));
            }
        } else {
            // Class of the field will have its own table
            memberTable = storeMgr.getDatastoreClass(mapping.getType(), clr);
        }
        DiscriminatorMetaData dismd = memberTable.getDiscriminatorMetaData();
        DiscriminatorMapping discMapping = (DiscriminatorMapping) memberTable.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, false);
        if (discMapping != null) {
            SQLTable targetSqlTbl = null;
            if (mapping.getTable() != memberTable) {
                // FK is on source table so inner join to target table (holding the discriminator)
                targetSqlTbl = stmt.getTable(memberTable, null);
                if (targetSqlTbl == null) {
                    targetSqlTbl = stmt.join(JoinType.INNER_JOIN, getSQLTable(), mapping, memberTable, null, memberTable.getIdMapping(), null, null);
                }
            } else {
                // FK is on target side and already joined
                targetSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, getSQLTable(), discMapping);
            }
            // Add restrict to discriminator for the instanceOf type and subclasses
            SQLTable discSqlTbl = targetSqlTbl;
            BooleanExpression discExpr = null;
            if (!Modifier.isAbstract(type.getModifiers())) {
                discExpr = SQLStatementHelper.getExpressionForDiscriminatorForClass(stmt, type.getName(), dismd, discMapping, discSqlTbl, clr);
            }
            Iterator<String> subclassIter = storeMgr.getSubClassesForClass(type.getName(), true, clr).iterator();
            boolean multiplePossibles = false;
            while (subclassIter.hasNext()) {
                String subclassName = subclassIter.next();
                Class subclass = clr.classForName(subclassName);
                if (Modifier.isAbstract(subclass.getModifiers())) {
                    continue;
                }
                BooleanExpression discExprSub = SQLStatementHelper.getExpressionForDiscriminatorForClass(stmt, subclassName, dismd, discMapping, discSqlTbl, clr);
                if (discExpr != null) {
                    multiplePossibles = true;
                    discExpr = discExpr.ior(discExprSub);
                } else {
                    discExpr = discExprSub;
                }
            }
            if (multiplePossibles && discExpr != null) {
                discExpr.encloseInParentheses();
            }
            return ((not && discExpr != null) ? discExpr.not() : discExpr);
        }
        // No discriminator, so the following is likely incomplete.
        // Join to member table
        DatastoreClass table = null;
        if (memberCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUBCLASS_TABLE) {
            // Field is a PC class that uses "subclass-table" inheritance strategy (and so has multiple possible tables to join to)
            AbstractClassMetaData[] cmds = storeMgr.getClassesManagingTableForClass(memberCmd, clr);
            if (cmds != null) {
                // TODO Allow for all possible tables. Can we do an OR of the tables ? How ?
                if (cmds.length > 1) {
                    NucleusLogger.QUERY.warn(Localiser.msg("037006", mapping.getMemberMetaData().getFullFieldName(), cmds[0].getFullClassName()));
                }
                table = storeMgr.getDatastoreClass(cmds[0].getFullClassName(), clr);
            } else {
                // No subclasses with tables to join to, so throw a user error
                throw new NucleusUserException(Localiser.msg("037005", mapping.getMemberMetaData().getFullFieldName()));
            }
        } else {
            // Class of the field will have its own table
            table = storeMgr.getDatastoreClass(mapping.getType(), clr);
        }
        if (table.managesClass(type.getName())) {
            // This type is managed in this table so must be an instance TODO Is this correct, what if member is using discrim?
            JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
            return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, !not));
        }
        if (table == stmt.getPrimaryTable().getTable()) {
            // This is member table, so just need to restrict to the instanceof type now
            JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
            if (stmt instanceof SelectStatement) {
                SelectStatement selectStmt = (SelectStatement) stmt;
                if (selectStmt.getNumberOfUnions() == 0) {
                    // No UNIONs so just check the main statement and return according to whether it is allowed
                    Class mainCandidateCls = clr.classForName(stmt.getCandidateClassName());
                    if (type.isAssignableFrom(mainCandidateCls) == not) {
                        SQLExpression returnExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
                        return (BooleanExpression) returnExpr;
                    }
                    SQLExpression returnExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
                    return (BooleanExpression) returnExpr;
                }
                NucleusLogger.QUERY.warn("TYPE/INSTANCEOF operator for class=" + memberCmd.getFullClassName() + " on table=" + memberTable + " for type=" + instanceofClassName + " but there is no discriminator and using UNIONs. Any subsequent handling is likely incorrect TODO");
                // a). we have unions for the member, so restrict to just the applicable unions
                // Note that this is only really valid is wanting "a instanceof SUB1".
                // It fails when we want to do "a instanceof SUB1 || a instanceof SUB2"
                // TODO What if this "OP_IS" is in the SELECT clause??? Need to update QueryToSQLMapper.compileResult
                Class mainCandidateCls = clr.classForName(stmt.getCandidateClassName());
                if (type.isAssignableFrom(mainCandidateCls) == not) {
                    SQLExpression unionClauseExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, false));
                    stmt.whereAnd((BooleanExpression) unionClauseExpr, false);
                }
                List<SelectStatement> unionStmts = selectStmt.getUnions();
                for (SelectStatement unionStmt : unionStmts) {
                    Class unionCandidateCls = clr.classForName(unionStmt.getCandidateClassName());
                    if (type.isAssignableFrom(unionCandidateCls) == not) {
                        SQLExpression unionClauseExpr = exprFactory.newLiteral(unionStmt, m, true).eq(exprFactory.newLiteral(unionStmt, m, false));
                        // TODO Avoid using whereAnd
                        unionStmt.whereAnd((BooleanExpression) unionClauseExpr, false);
                    }
                }
                // Just return true since we applied the condition direct to the unions
                SQLExpression returnExpr = exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, true));
                return (BooleanExpression) returnExpr;
            }
            // b). The member table doesn't manage the instanceof type, so do inner join to
            // the table of the instanceof to impose the instanceof condition
            DatastoreClass instanceofTable = storeMgr.getDatastoreClass(type.getName(), clr);
            stmt.join(JoinType.INNER_JOIN, this.table, this.table.getTable().getIdMapping(), instanceofTable, null, instanceofTable.getIdMapping(), null, this.table.getGroupName());
            return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, !not));
        }
        // Do inner join to this table to impose the instanceOf
        DatastoreClass instanceofTable = storeMgr.getDatastoreClass(type.getName(), clr);
        stmt.join(JoinType.INNER_JOIN, this.table, this.table.getTable().getIdMapping(), instanceofTable, null, instanceofTable.getIdMapping(), null, this.table.getGroupName());
        JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
        return exprFactory.newLiteral(stmt, m, true).eq(exprFactory.newLiteral(stmt, m, !not));
    } else {
        // TODO Implement instanceof for other types
        throw new NucleusException("Dont currently support " + this + " instanceof " + type.getName());
    }
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) Iterator(java.util.Iterator) LinkedList(java.util.LinkedList) List(java.util.List) DiscriminatorMapping(org.datanucleus.store.rdbms.mapping.java.DiscriminatorMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) ClassNotResolvedException(org.datanucleus.exceptions.ClassNotResolvedException) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) DiscriminatorMetaData(org.datanucleus.metadata.DiscriminatorMetaData) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) EmbeddedMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedMapping) Collection(java.util.Collection) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) NucleusException(org.datanucleus.exceptions.NucleusException)

Example 7 with ReferenceMapping

use of org.datanucleus.store.rdbms.mapping.java.ReferenceMapping in project datanucleus-rdbms by datanucleus.

the class ObjectExpression method cast.

/**
 * Cast operator. Called when the query contains "(type)obj" where "obj" is this object.
 * @param expr Expression representing the type to cast to
 * @return Scalar expression representing the cast object.
 */
public SQLExpression cast(SQLExpression expr) {
    RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
    ClassLoaderResolver clr = stmt.getClassLoaderResolver();
    // Extract cast type
    String castClassName = (String) ((StringLiteral) expr).getValue();
    Class type = null;
    try {
        type = stmt.getQueryGenerator().resolveClass(castClassName);
    } catch (ClassNotResolvedException cnre) {
        type = null;
    }
    if (type == null) {
        throw new NucleusUserException(Localiser.msg("037017", castClassName));
    }
    // Extract type of this object and check obvious conditions
    SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
    Class memberType = clr.classForName(mapping.getType());
    if (!memberType.isAssignableFrom(type) && !type.isAssignableFrom(memberType)) {
        // object type and cast type are totally incompatible, so just return false
        JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
        return exprFactory.newLiteral(stmt, m, false).eq(exprFactory.newLiteral(stmt, m, true));
    } else if (memberType == type) {
        // Just return this expression since it is already castable
        return this;
    }
    if (mapping instanceof EmbeddedMapping) {
        // Don't support embedded casts
        JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
        return exprFactory.newLiteral(stmt, m, false).eq(exprFactory.newLiteral(stmt, m, true));
    } else if (mapping instanceof ReferenceMapping) {
        // This expression will be for the table containing the reference so need to join now
        ReferenceMapping refMapping = (ReferenceMapping) mapping;
        if (refMapping.getMappingStrategy() != ReferenceMapping.PER_IMPLEMENTATION_MAPPING) {
            throw new NucleusUserException("Impossible to do cast of interface to " + type.getName() + " since interface is persisted as embedded String." + " Use per-implementation mapping to allow this query");
        }
        JavaTypeMapping[] implMappings = refMapping.getJavaTypeMapping();
        for (int i = 0; i < implMappings.length; i++) {
            Class implType = clr.classForName(implMappings[i].getType());
            if (type.isAssignableFrom(implType)) {
                DatastoreClass castTable = storeMgr.getDatastoreClass(type.getName(), clr);
                SQLTable castSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, table, implMappings[i], refMapping, castTable, null, castTable.getIdMapping(), null, null, null, true, null);
                return exprFactory.newExpression(stmt, castSqlTbl, castTable.getIdMapping());
            }
        }
        // No implementation matching this cast type, so return false
        NucleusLogger.QUERY.warn("Unable to process cast of interface field to " + type.getName() + " since it has no implementations that match that type");
        JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
        return exprFactory.newLiteral(stmt, m, false).eq(exprFactory.newLiteral(stmt, m, true));
    } else if (mapping instanceof PersistableMapping) {
        // Check if there is already the cast table in the current table group
        DatastoreClass castTable = storeMgr.getDatastoreClass(type.getName(), clr);
        SQLTable castSqlTbl = stmt.getTable(castTable, table.getGroupName());
        if (castSqlTbl == null) {
            // Join not present, so join to the cast table
            castSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, table, table.getTable().getIdMapping(), castTable, null, castTable.getIdMapping(), null, table.getGroupName());
        }
        if (castSqlTbl == table) {
            AbstractClassMetaData castCmd = storeMgr.getMetaDataManager().getMetaDataForClass(type, clr);
            if (castCmd.hasDiscriminatorStrategy()) {
                // TODO How do we handle this? If this is part of the filter then need to hang a BooleanExpression off the ObjectExpression and apply later.
                // If this is part of the result, do we just return null when this is not the right type?
                NucleusLogger.QUERY.warn(">> Currently do not support adding restriction on discriminator for table=" + table + " to " + type);
            }
        }
        // Return an expression based on the cast table
        return exprFactory.newExpression(stmt, castSqlTbl, castTable.getIdMapping());
    } else {
    // TODO Handle other casts
    }
    // TODO Implement cast (left outer join to table of type, then return new ObjectExpression)
    throw new NucleusUserException("Dont currently support ObjectExpression.cast(" + type + ")");
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) ClassNotResolvedException(org.datanucleus.exceptions.ClassNotResolvedException) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) EmbeddedMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedMapping) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass)

Example 8 with ReferenceMapping

use of org.datanucleus.store.rdbms.mapping.java.ReferenceMapping in project datanucleus-rdbms by datanucleus.

the class JoinSetStore method iterator.

@Override
public Iterator<E> iterator(DNStateManager ownerSM) {
    ExecutionContext ec = ownerSM.getExecutionContext();
    // Generate the statement, and statement mapping/parameter information
    ElementIteratorStatement iterStmt = getIteratorStatement(ec, ec.getFetchPlan(), true);
    SelectStatement sqlStmt = iterStmt.sqlStmt;
    StatementClassMapping iteratorMappingClass = iterStmt.elementClassMapping;
    // Input parameter(s) - the owner
    int inputParamNum = 1;
    StatementMappingIndex ownerStmtMapIdx = new StatementMappingIndex(ownerMapping);
    if (sqlStmt.getNumberOfUnions() > 0) {
        // Add parameter occurrence for each union of statement
        for (int j = 0; j < sqlStmt.getNumberOfUnions() + 1; j++) {
            int[] paramPositions = new int[ownerMapping.getNumberOfColumnMappings()];
            for (int k = 0; k < paramPositions.length; k++) {
                paramPositions[k] = inputParamNum++;
            }
            ownerStmtMapIdx.addParameterOccurrence(paramPositions);
        }
    } else {
        int[] paramPositions = new int[ownerMapping.getNumberOfColumnMappings()];
        for (int k = 0; k < paramPositions.length; k++) {
            paramPositions[k] = inputParamNum++;
        }
        ownerStmtMapIdx.addParameterOccurrence(paramPositions);
    }
    if (ec.getTransaction().getSerializeRead() != null && ec.getTransaction().getSerializeRead()) {
        sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
    }
    String stmt = sqlStmt.getSQLText().toSQL();
    try {
        ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
        SQLController sqlControl = storeMgr.getSQLController();
        try {
            // Create the statement
            PreparedStatement ps = sqlControl.getStatementForQuery(mconn, stmt);
            // Set the owner
            DNStateManager stmtOwnerSM = BackingStoreHelper.getOwnerStateManagerForBackingStore(ownerSM);
            int numParams = ownerStmtMapIdx.getNumberOfParameterOccurrences();
            for (int paramInstance = 0; paramInstance < numParams; paramInstance++) {
                ownerStmtMapIdx.getMapping().setObject(ec, ps, ownerStmtMapIdx.getParameterPositionsForOccurrence(paramInstance), stmtOwnerSM.getObject());
            }
            try {
                ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, stmt, ps);
                try {
                    if (elementsAreEmbedded || elementsAreSerialised) {
                        // No ResultObjectFactory needed - handled by SetStoreIterator
                        return new CollectionStoreIterator(ownerSM, rs, null, this);
                    } else if (elementMapping instanceof ReferenceMapping) {
                        // No ResultObjectFactory needed - handled by SetStoreIterator
                        return new CollectionStoreIterator(ownerSM, rs, null, this);
                    } else {
                        ResultObjectFactory rof = new PersistentClassROF(ec, rs, false, ec.getFetchPlan(), iteratorMappingClass, elementCmd, clr.classForName(elementType));
                        return new CollectionStoreIterator(ownerSM, rs, rof, this);
                    }
                } finally {
                    rs.close();
                }
            } finally {
                sqlControl.closeStatement(mconn, ps);
            }
        } finally {
            mconn.release();
        }
    } catch (SQLException e) {
        throw new NucleusDataStoreException(Localiser.msg("056006", stmt), e);
    }
}
Also used : SQLException(java.sql.SQLException) ResultObjectFactory(org.datanucleus.store.rdbms.query.ResultObjectFactory) PreparedStatement(java.sql.PreparedStatement) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) SQLController(org.datanucleus.store.rdbms.SQLController) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) ExecutionContext(org.datanucleus.ExecutionContext) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) PersistentClassROF(org.datanucleus.store.rdbms.query.PersistentClassROF) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) DNStateManager(org.datanucleus.state.DNStateManager)

Example 9 with ReferenceMapping

use of org.datanucleus.store.rdbms.mapping.java.ReferenceMapping in project datanucleus-rdbms by datanucleus.

the class JoinListStore method listIterator.

/**
 * Accessor for an iterator through the list elements.
 * @param ownerSM StateManager for the list owner
 * @param startIdx The start point in the list (only for indexed lists).
 * @param endIdx End index in the list (only for indexed lists).
 * @return The List Iterator
 */
protected ListIterator<E> listIterator(DNStateManager ownerSM, int startIdx, int endIdx) {
    ExecutionContext ec = ownerSM.getExecutionContext();
    // Generate the statement. Note that this is not cached since depends on the current FetchPlan and other things
    ElementIteratorStatement iterStmt = getIteratorStatement(ownerSM.getExecutionContext(), ec.getFetchPlan(), true, startIdx, endIdx);
    SelectStatement sqlStmt = iterStmt.getSelectStatement();
    StatementClassMapping resultMapping = iterStmt.getElementClassMapping();
    // Input parameter(s) - the owner
    int inputParamNum = 1;
    StatementMappingIndex ownerIdx = new StatementMappingIndex(ownerMapping);
    if (sqlStmt.getNumberOfUnions() > 0) {
        // Add parameter occurrence for each union of statement
        for (int j = 0; j < sqlStmt.getNumberOfUnions() + 1; j++) {
            int[] paramPositions = new int[ownerMapping.getNumberOfColumnMappings()];
            for (int k = 0; k < paramPositions.length; k++) {
                paramPositions[k] = inputParamNum++;
            }
            ownerIdx.addParameterOccurrence(paramPositions);
        }
    } else {
        int[] paramPositions = new int[ownerMapping.getNumberOfColumnMappings()];
        for (int k = 0; k < paramPositions.length; k++) {
            paramPositions[k] = inputParamNum++;
        }
        ownerIdx.addParameterOccurrence(paramPositions);
    }
    Boolean serializeRead = ec.getTransaction().getSerializeRead();
    if (serializeRead != null && serializeRead) {
        sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
    }
    String stmt = sqlStmt.getSQLText().toSQL();
    try {
        ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
        SQLController sqlControl = storeMgr.getSQLController();
        try {
            // Create the statement
            PreparedStatement ps = sqlControl.getStatementForQuery(mconn, stmt);
            // Set the owner
            DNStateManager stmtOwnerSM = BackingStoreHelper.getOwnerStateManagerForBackingStore(ownerSM);
            int numParams = ownerIdx.getNumberOfParameterOccurrences();
            for (int paramInstance = 0; paramInstance < numParams; paramInstance++) {
                ownerIdx.getMapping().setObject(ec, ps, ownerIdx.getParameterPositionsForOccurrence(paramInstance), stmtOwnerSM.getObject());
            }
            try {
                ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, stmt, ps);
                try {
                    if (elementsAreEmbedded || elementsAreSerialised) {
                        // No ResultObjectFactory needed - handled by SetStoreIterator
                        return new ListStoreIterator(ownerSM, rs, null, this);
                    } else if (elementMapping instanceof ReferenceMapping) {
                        // No ResultObjectFactory needed - handled by SetStoreIterator
                        return new ListStoreIterator(ownerSM, rs, null, this);
                    } else {
                        ResultObjectFactory rof = new PersistentClassROF(ec, rs, false, ec.getFetchPlan(), resultMapping, elementCmd, clr.classForName(elementType));
                        return new ListStoreIterator(ownerSM, rs, rof, this);
                    }
                } finally {
                    rs.close();
                }
            } finally {
                sqlControl.closeStatement(mconn, ps);
            }
        } finally {
            mconn.release();
        }
    } catch (SQLException e) {
        throw new NucleusDataStoreException(Localiser.msg("056006", stmt), e);
    }
}
Also used : SQLException(java.sql.SQLException) ResultObjectFactory(org.datanucleus.store.rdbms.query.ResultObjectFactory) PreparedStatement(java.sql.PreparedStatement) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) SQLController(org.datanucleus.store.rdbms.SQLController) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) ExecutionContext(org.datanucleus.ExecutionContext) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) PersistentClassROF(org.datanucleus.store.rdbms.query.PersistentClassROF) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) DNStateManager(org.datanucleus.state.DNStateManager)

Example 10 with ReferenceMapping

use of org.datanucleus.store.rdbms.mapping.java.ReferenceMapping in project datanucleus-rdbms by datanucleus.

the class JoinListStore method getIteratorStatement.

/**
 * Method to return the SQLStatement and mapping for an iterator for this backing store.
 * Create a statement of the form
 * <pre>
 * SELECT ELEM_COLS
 * FROM JOIN_TBL
 *   [JOIN ELEM_TBL ON ELEM_TBL.ID = JOIN_TBL.ELEM_ID]
 * [WHERE]
 *   [JOIN_TBL.OWNER_ID = {value}] [AND]
 *   [JOIN_TBL.DISCRIM = {discrimValue}]
 * [ORDER BY {orderClause}]
 * </pre>
 * This is public to provide access for BulkFetchXXXHandler class(es).
 * @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 ElementIteratorStatement getIteratorStatement(ExecutionContext ec, FetchPlan fp, boolean addRestrictionOnOwner, int startIdx, int endIdx) {
    SelectStatement sqlStmt = null;
    StatementClassMapping elementClsMapping = new StatementClassMapping();
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    if (elementsAreEmbedded || elementsAreSerialised) {
        // Element = embedded, serialised (maybe Non-PC)
        // Just select the join table since we're going to return the embedded/serialised columns from it
        sqlStmt = new SelectStatement(storeMgr, containerTable, null, null);
        sqlStmt.setClassLoaderResolver(clr);
        // Select the element column - first select is assumed by ListStoreIterator
        sqlStmt.select(sqlStmt.getPrimaryTable(), elementMapping, null);
    // TODO If embedded element and it includes 1-1/N-1 in FetchPlan then select its fields also
    } else if (elementMapping instanceof ReferenceMapping) {
        // Element = Reference type (interface/Object)
        // Just select the join table since we're going to return the implementation id columns only
        sqlStmt = new SelectStatement(storeMgr, containerTable, null, null);
        sqlStmt.setClassLoaderResolver(clr);
        // Select the reference column(s) - first select is assumed by ListStoreIterator
        sqlStmt.select(sqlStmt.getPrimaryTable(), elementMapping, null);
    } else {
        // Join to the element table(s)
        if (elementInfo != null) {
            for (int i = 0; i < elementInfo.length; i++) {
                // TODO This will only work if all element types have a discriminator
                final int elementNo = i;
                final Class elementCls = clr.classForName(elementInfo[elementNo].getClassName());
                SelectStatement elementStmt = null;
                if (elementInfo[elementNo].getDiscriminatorStrategy() != null && elementInfo[elementNo].getDiscriminatorStrategy() != DiscriminatorStrategy.NONE) {
                    // The element uses a discriminator so just use that in the SELECT
                    String elementType = ownerMemberMetaData.getCollection().getElementType();
                    if (ClassUtils.isReferenceType(clr.classForName(elementType))) {
                        String[] clsNames = storeMgr.getNucleusContext().getMetaDataManager().getClassesImplementingInterface(elementType, clr);
                        Class[] cls = new Class[clsNames.length];
                        for (int j = 0; j < clsNames.length; j++) {
                            cls[j] = clr.classForName(clsNames[j]);
                        }
                        SelectStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, cls, true, null, null, containerTable, null, elementMapping);
                        if (allowNulls) {
                            stmtGen.setOption(SelectStatementGenerator.OPTION_ALLOW_NULLS);
                        }
                        elementStmt = stmtGen.getStatement(ec);
                    } else {
                        SelectStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, elementCls, true, null, null, containerTable, null, elementMapping);
                        if (allowNulls) {
                            stmtGen.setOption(SelectStatementGenerator.OPTION_ALLOW_NULLS);
                        }
                        elementStmt = stmtGen.getStatement(ec);
                    }
                    iterateUsingDiscriminator = true;
                } else {
                    // No discriminator, but subclasses so use UNIONs
                    SelectStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, elementCls, true, null, null, containerTable, null, elementMapping);
                    stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                    elementClsMapping.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
                    elementStmt = stmtGen.getStatement(ec);
                }
                if (sqlStmt == null) {
                    sqlStmt = elementStmt;
                } else {
                    sqlStmt.union(elementStmt);
                }
            }
            if (sqlStmt == null) {
                throw new NucleusException("Error in generation of SQL statement for iterator over (Join) list. Statement is null");
            }
            // Select the required fields
            SQLTable elementSqlTbl = sqlStmt.getTable(elementInfo[0].getDatastoreClass(), sqlStmt.getPrimaryTable().getGroupName());
            SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, elementClsMapping, fp, elementSqlTbl, elementCmd, fp.getMaxFetchDepth());
        } else {
            throw new NucleusException("Unable to create SQL statement to retrieve elements of List");
        }
    }
    if (addRestrictionOnOwner) {
        // Apply condition on join-table owner field to filter by owner
        SQLTable ownerSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), ownerMapping);
        SQLExpression ownerExpr = exprFactory.newExpression(sqlStmt, ownerSqlTbl, ownerMapping);
        SQLExpression ownerVal = exprFactory.newLiteralParameter(sqlStmt, ownerMapping, null, "OWNER");
        sqlStmt.whereAnd(ownerExpr.eq(ownerVal), true);
    }
    if (relationDiscriminatorMapping != null) {
        // Apply condition on distinguisher field to filter by distinguisher (when present)
        SQLTable distSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), relationDiscriminatorMapping);
        SQLExpression distExpr = exprFactory.newExpression(sqlStmt, distSqlTbl, relationDiscriminatorMapping);
        SQLExpression distVal = exprFactory.newLiteral(sqlStmt, relationDiscriminatorMapping, relationDiscriminatorValue);
        sqlStmt.whereAnd(distExpr.eq(distVal), true);
    }
    if (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, when present
            SQLTable orderSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), orderMapping);
            SQLExpression[] orderExprs = new SQLExpression[orderMapping.getNumberOfColumnMappings()];
            boolean[] descendingOrder = new boolean[orderMapping.getNumberOfColumnMappings()];
            orderExprs[0] = exprFactory.newExpression(sqlStmt, orderSqlTbl, orderMapping);
            sqlStmt.setOrdering(orderExprs, descendingOrder);
        }
    } else {
        if (elementInfo != null) {
            // 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 ElementIteratorStatement(this, sqlStmt, elementClsMapping);
}
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) SelectStatementGenerator(org.datanucleus.store.rdbms.sql.SelectStatementGenerator) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) DiscriminatorStatementGenerator(org.datanucleus.store.rdbms.sql.DiscriminatorStatementGenerator) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) NucleusException(org.datanucleus.exceptions.NucleusException)

Aggregations

ReferenceMapping (org.datanucleus.store.rdbms.mapping.java.ReferenceMapping)38 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)23 PersistableMapping (org.datanucleus.store.rdbms.mapping.java.PersistableMapping)16 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)14 StatementMappingIndex (org.datanucleus.store.rdbms.query.StatementMappingIndex)13 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)13 ExecutionContext (org.datanucleus.ExecutionContext)12 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)12 SQLException (java.sql.SQLException)11 PersistentClassROF (org.datanucleus.store.rdbms.query.PersistentClassROF)11 StatementClassMapping (org.datanucleus.store.rdbms.query.StatementClassMapping)11 PreparedStatement (java.sql.PreparedStatement)10 ResultSet (java.sql.ResultSet)10 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)10 ManagedConnection (org.datanucleus.store.connection.ManagedConnection)10 SQLController (org.datanucleus.store.rdbms.SQLController)10 ResultObjectFactory (org.datanucleus.store.rdbms.query.ResultObjectFactory)10 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)10 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)8 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)7