Search in sources :

Example 11 with StatementClassMapping

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

the class JoinListStore method listIterator.

/**
 * Accessor for an iterator through the list elements.
 * @param ownerOP ObjectProvider for the 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(ObjectProvider ownerOP, int startIdx, int endIdx) {
    ExecutionContext ec = ownerOP.getExecutionContext();
    Transaction tx = ec.getTransaction();
    // Generate the statement. Note that this is not cached since depends on the current FetchPlan and other things
    IteratorStatement iterStmt = getIteratorStatement(ownerOP.getExecutionContext(), ec.getFetchPlan(), true, startIdx, endIdx);
    SelectStatement sqlStmt = iterStmt.getSelectStatement();
    StatementClassMapping resultMapping = iterStmt.getStatementClassMapping();
    // 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.getNumberOfDatastoreMappings()];
            for (int k = 0; k < paramPositions.length; k++) {
                paramPositions[k] = inputParamNum++;
            }
            ownerIdx.addParameterOccurrence(paramPositions);
        }
    } else {
        int[] paramPositions = new int[ownerMapping.getNumberOfDatastoreMappings()];
        for (int k = 0; k < paramPositions.length; k++) {
            paramPositions[k] = inputParamNum++;
        }
        ownerIdx.addParameterOccurrence(paramPositions);
    }
    if (tx.getSerializeRead() != null && tx.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
            ObjectProvider stmtOwnerOP = BackingStoreHelper.getOwnerObjectProviderForBackingStore(ownerOP);
            int numParams = ownerIdx.getNumberOfParameterOccurrences();
            for (int paramInstance = 0; paramInstance < numParams; paramInstance++) {
                ownerIdx.getMapping().setObject(ec, ps, ownerIdx.getParameterPositionsForOccurrence(paramInstance), stmtOwnerOP.getObject());
            }
            try {
                ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, stmt, ps);
                try {
                    if (elementsAreEmbedded || elementsAreSerialised) {
                        // No ResultObjectFactory needed - handled by SetStoreIterator
                        return new ListStoreIterator(ownerOP, rs, null, this);
                    } else if (elementMapping instanceof ReferenceMapping) {
                        // No ResultObjectFactory needed - handled by SetStoreIterator
                        return new ListStoreIterator(ownerOP, rs, null, this);
                    } else {
                        ResultObjectFactory rof = new PersistentClassROF(ec, rs, false, resultMapping, elementCmd, clr.classForName(elementType));
                        return new ListStoreIterator(ownerOP, rs, rof, this);
                    }
                } finally {
                    rs.close();
                }
            } finally {
                sqlControl.closeStatement(mconn, ps);
            }
        } finally {
            mconn.release();
        }
    } catch (SQLException | MappedDatastoreException e) {
        throw new NucleusDataStoreException(Localiser.msg("056006", stmt), e);
    }
}
Also used : MappedDatastoreException(org.datanucleus.store.rdbms.exceptions.MappedDatastoreException) 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) Transaction(org.datanucleus.Transaction) PersistentClassROF(org.datanucleus.store.rdbms.query.PersistentClassROF) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) ObjectProvider(org.datanucleus.state.ObjectProvider)

Example 12 with StatementClassMapping

use of org.datanucleus.store.rdbms.query.StatementClassMapping 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>
 * @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 (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);
                    stmtClassMapping.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, stmtClassMapping, 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.getNumberOfDatastoreMappings()];
            boolean[] descendingOrder = new boolean[orderMapping.getNumberOfDatastoreMappings()];
            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 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) 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)

Example 13 with StatementClassMapping

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

the class BackingStoreHelper method populateEmbeddedElementFieldsInStatement.

/**
 * Convenience method to populate the passed PreparedStatement with the field values from
 * the embedded element starting at the specified jdbc position.
 * @param op ObjectProvider of the owning container
 * @param element The embedded element
 * @param ps The PreparedStatement
 * @param jdbcPosition JDBC position in the statement to start at
 * @param ownerFieldMetaData The meta data for the owner field
 * @param elementMapping mapping for the element
 * @param emd Metadata for the element class
 * @param bcs Container store
 * @return The next JDBC position
 */
public static int populateEmbeddedElementFieldsInStatement(ObjectProvider op, Object element, PreparedStatement ps, int jdbcPosition, AbstractMemberMetaData ownerFieldMetaData, JavaTypeMapping elementMapping, AbstractClassMetaData emd, BaseContainerStore bcs) {
    EmbeddedElementPCMapping embeddedMapping = (EmbeddedElementPCMapping) elementMapping;
    StatementClassMapping mappingDefinition = new StatementClassMapping();
    int[] elementFieldNumbers = new int[embeddedMapping.getNumberOfJavaTypeMappings()];
    for (int i = 0; i < embeddedMapping.getNumberOfJavaTypeMappings(); i++) {
        JavaTypeMapping fieldMapping = embeddedMapping.getJavaTypeMapping(i);
        int absFieldNum = emd.getAbsolutePositionOfMember(fieldMapping.getMemberMetaData().getName());
        elementFieldNumbers[i] = absFieldNum;
        StatementMappingIndex stmtMapping = new StatementMappingIndex(fieldMapping);
        int[] jdbcParamPositions = new int[fieldMapping.getNumberOfDatastoreMappings()];
        for (int j = 0; j < fieldMapping.getNumberOfDatastoreMappings(); j++) {
            jdbcParamPositions[j] = jdbcPosition++;
        }
        stmtMapping.addParameterOccurrence(jdbcParamPositions);
        mappingDefinition.addMappingForMember(absFieldNum, stmtMapping);
    }
    ObjectProvider elementOP = bcs.getObjectProviderForEmbeddedPCObject(op, element, ownerFieldMetaData, ObjectProvider.EMBEDDED_COLLECTION_ELEMENT_PC);
    elementOP.provideFields(elementFieldNumbers, new ParameterSetter(elementOP, ps, mappingDefinition));
    return jdbcPosition;
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ObjectProvider(org.datanucleus.state.ObjectProvider) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) ParameterSetter(org.datanucleus.store.rdbms.fieldmanager.ParameterSetter) EmbeddedElementPCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedElementPCMapping) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping)

Example 14 with StatementClassMapping

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

the class UpdateRequest method execute.

/**
 * Method performing the update of the record in the datastore.
 * Takes the constructed update query and populates with the specific record information.
 * @param op The ObjectProvider for the record to be updated
 */
public void execute(ObjectProvider op) {
    // Choose the statement based on whether optimistic or not
    String stmt = null;
    ExecutionContext ec = op.getExecutionContext();
    boolean optimisticChecks = (versionMetaData != null && ec.getTransaction().getOptimistic() && versionChecks);
    stmt = optimisticChecks ? updateStmtOptimistic : updateStmt;
    if (stmt != null) {
        // TODO Support surrogate update user/timestamp
        AbstractMemberMetaData[] mmds = cmd.getManagedMembers();
        for (int i = 0; i < mmds.length; i++) {
            if (// TODO Make this accessible from cmd
            mmds[i].isUpdateTimestamp()) {
                op.replaceField(mmds[i].getAbsoluteFieldNumber(), new Timestamp(ec.getTransaction().getIsActive() ? ec.getTransaction().getBeginTime() : System.currentTimeMillis()));
            } else if (// TODO Make this accessible from cmd
            mmds[i].isUpdateUser()) {
                op.replaceField(mmds[i].getAbsoluteFieldNumber(), ec.getNucleusContext().getCurrentUser(ec));
            }
        }
        if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
            // Debug info about fields being updated
            StringBuilder fieldStr = new StringBuilder();
            if (updateFieldNumbers != null) {
                for (int i = 0; i < updateFieldNumbers.length; i++) {
                    if (fieldStr.length() > 0) {
                        fieldStr.append(",");
                    }
                    fieldStr.append(cmd.getMetaDataForManagedMemberAtAbsolutePosition(updateFieldNumbers[i]).getName());
                }
            }
            if (versionMetaData != null && versionMetaData.getFieldName() == null) {
                if (fieldStr.length() > 0) {
                    fieldStr.append(",");
                }
                fieldStr.append("[VERSION]");
            }
            // Debug information about what we are updating
            NucleusLogger.PERSISTENCE.debug(Localiser.msg("052214", op.getObjectAsPrintable(), fieldStr.toString(), table));
        }
        RDBMSStoreManager storeMgr = table.getStoreManager();
        boolean batch = false;
        // TODO Set the batch flag based on whether we have no other SQL being invoked in here just our UPDATE
        try {
            ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            try {
                // Perform the update
                PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, stmt, batch);
                try {
                    Object currentVersion = op.getTransactionalVersion();
                    Object nextVersion = null;
                    if (// TODO What if strategy is NONE?
                    versionMetaData != null) {
                        // Set the next version in the object
                        if (versionMetaData.getFieldName() != null) {
                            // Version field
                            AbstractMemberMetaData verfmd = cmd.getMetaDataForMember(table.getVersionMetaData().getFieldName());
                            if (currentVersion instanceof Number) {
                                // Cater for Integer-based versions
                                currentVersion = Long.valueOf(((Number) currentVersion).longValue());
                            }
                            nextVersion = ec.getLockManager().getNextVersion(versionMetaData, currentVersion);
                            if (verfmd.getType() == Integer.class || verfmd.getType() == int.class) {
                                // Cater for Integer-based versions
                                nextVersion = Integer.valueOf(((Number) nextVersion).intValue());
                            }
                            op.replaceField(verfmd.getAbsoluteFieldNumber(), nextVersion);
                        } else {
                            // Surrogate version column
                            nextVersion = ec.getLockManager().getNextVersion(versionMetaData, currentVersion);
                        }
                        op.setTransactionalVersion(nextVersion);
                    }
                    // SELECT clause - set the required fields to be updated
                    if (updateFieldNumbers != null) {
                        StatementClassMapping mappingDefinition = new StatementClassMapping();
                        StatementMappingIndex[] idxs = stmtMappingDefinition.getUpdateFields();
                        for (int i = 0; i < idxs.length; i++) {
                            if (idxs[i] != null) {
                                mappingDefinition.addMappingForMember(i, idxs[i]);
                            }
                        }
                        op.provideFields(updateFieldNumbers, new ParameterSetter(op, ps, mappingDefinition));
                    }
                    if (versionMetaData != null && versionMetaData.getFieldName() == null) {
                        // SELECT clause - set the surrogate version column to the new version
                        StatementMappingIndex mapIdx = stmtMappingDefinition.getUpdateVersion();
                        for (int i = 0; i < mapIdx.getNumberOfParameterOccurrences(); i++) {
                            table.getSurrogateMapping(SurrogateColumnType.VERSION, false).setObject(ec, ps, mapIdx.getParameterPositionsForOccurrence(i), nextVersion);
                        }
                    }
                    // WHERE clause - primary key fields
                    if (table.getIdentityType() == IdentityType.DATASTORE) {
                        // a). datastore identity
                        StatementMappingIndex mapIdx = stmtMappingDefinition.getWhereDatastoreId();
                        for (int i = 0; i < mapIdx.getNumberOfParameterOccurrences(); i++) {
                            table.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false).setObject(ec, ps, mapIdx.getParameterPositionsForOccurrence(i), op.getInternalObjectId());
                        }
                    } else {
                        // b). application/nondurable identity
                        StatementClassMapping mappingDefinition = new StatementClassMapping();
                        StatementMappingIndex[] idxs = stmtMappingDefinition.getWhereFields();
                        for (int i = 0; i < idxs.length; i++) {
                            if (idxs[i] != null) {
                                mappingDefinition.addMappingForMember(i, idxs[i]);
                            }
                        }
                        FieldManager fm = null;
                        if (cmd.getIdentityType() == IdentityType.NONDURABLE) {
                            fm = new OldValueParameterSetter(op, ps, mappingDefinition);
                        } else {
                            fm = new ParameterSetter(op, ps, mappingDefinition);
                        }
                        op.provideFields(whereFieldNumbers, fm);
                    }
                    if (optimisticChecks) {
                        if (currentVersion == null) {
                            // Somehow the version is not set on this object (not read in ?) so report the bug
                            String msg = Localiser.msg("052201", op.getInternalObjectId(), table);
                            NucleusLogger.PERSISTENCE.error(msg);
                            throw new NucleusException(msg);
                        }
                        // WHERE clause - current version discriminator
                        StatementMappingIndex mapIdx = stmtMappingDefinition.getWhereVersion();
                        for (int i = 0; i < mapIdx.getNumberOfParameterOccurrences(); i++) {
                            mapIdx.getMapping().setObject(ec, ps, mapIdx.getParameterPositionsForOccurrence(i), currentVersion);
                        }
                    }
                    int[] rcs = sqlControl.executeStatementUpdate(ec, mconn, stmt, ps, !batch);
                    if (rcs[0] == 0 && optimisticChecks) {
                        // TODO Batching : when we use batching here we need to process these somehow
                        throw new NucleusOptimisticException(Localiser.msg("052203", op.getObjectAsPrintable(), op.getInternalObjectId(), "" + currentVersion), op.getObject());
                    }
                } finally {
                    sqlControl.closeStatement(mconn, ps);
                }
            } finally {
                mconn.release();
            }
        } catch (SQLException e) {
            String msg = Localiser.msg("052215", op.getObjectAsPrintable(), stmt, StringUtils.getStringFromStackTrace(e));
            NucleusLogger.DATASTORE_PERSIST.error(msg);
            List exceptions = new ArrayList();
            exceptions.add(e);
            while ((e = e.getNextException()) != null) {
                exceptions.add(e);
            }
            throw new NucleusDataStoreException(msg, (Throwable[]) exceptions.toArray(new Throwable[exceptions.size()]));
        }
    }
    // Execute any mapping actions now that we have done the update
    for (int i = 0; i < callbacks.length; ++i) {
        try {
            if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                NucleusLogger.PERSISTENCE.debug(Localiser.msg("052216", op.getObjectAsPrintable(), ((JavaTypeMapping) callbacks[i]).getMemberMetaData().getFullFieldName()));
            }
            callbacks[i].postUpdate(op);
        } catch (NotYetFlushedException e) {
            op.updateFieldAfterInsert(e.getPersistable(), ((JavaTypeMapping) callbacks[i]).getMemberMetaData().getAbsoluteFieldNumber());
        }
    }
}
Also used : FieldManager(org.datanucleus.store.fieldmanager.FieldManager) SQLException(java.sql.SQLException) ArrayList(java.util.ArrayList) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) ParameterSetter(org.datanucleus.store.rdbms.fieldmanager.ParameterSetter) OldValueParameterSetter(org.datanucleus.store.rdbms.fieldmanager.OldValueParameterSetter) Timestamp(java.sql.Timestamp) SQLController(org.datanucleus.store.rdbms.SQLController) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) ArrayList(java.util.ArrayList) List(java.util.List) PreparedStatement(java.sql.PreparedStatement) NotYetFlushedException(org.datanucleus.exceptions.NotYetFlushedException) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) ExecutionContext(org.datanucleus.ExecutionContext) NucleusOptimisticException(org.datanucleus.exceptions.NucleusOptimisticException) OldValueParameterSetter(org.datanucleus.store.rdbms.fieldmanager.OldValueParameterSetter) NucleusException(org.datanucleus.exceptions.NucleusException) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 15 with StatementClassMapping

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

the class FKSetStore 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 determining which fields of element to select
 * @param addRestrictionOnOwner Whether to restrict to a particular owner (otherwise functions as bulk fetch for many owners).
 * @return The SQLStatement and its associated StatementClassMapping
 */
public IteratorStatement getIteratorStatement(ExecutionContext ec, FetchPlan fp, boolean addRestrictionOnOwner) {
    SelectStatement sqlStmt = null;
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    StatementClassMapping iteratorMappingClass = new StatementClassMapping();
    if (elementInfo[0].getDatastoreClass().getDiscriminatorMetaData() != null && elementInfo[0].getDatastoreClass().getDiscriminatorMetaData().getStrategy() != DiscriminatorStrategy.NONE) {
        // TODO Only caters for one elementInfo, but with subclass-table we can have multiple
        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;
        // TODO Cater for having all possible subclasses stored in the same table (so we can select their fields too)
        // String[] elemSubclasses = op.getExecutionContext().getMetaDataManager().getSubclassesForClass(emd.getFullClassName(), false);
        // NucleusLogger.GENERAL.info(">> FKSetStore.iter iterMapDef=" + iteratorMappingDef + " table=" + sqlStmt.getPrimaryTable() +
        // " emd=" + emd.getFullClassName() + " elem.subclasses=" + StringUtils.objectArrayToString(elemSubclasses));
        // Select the required fields (of the element class)
        SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(sqlStmt, iteratorMappingClass, fp, sqlStmt.getPrimaryTable(), elementCmd, fp.getMaxFetchDepth());
    } else {
        boolean selectFetchPlan = true;
        Class elementTypeCls = clr.classForName(elementType);
        if (elementTypeCls.isInterface() && elementInfo.length > 1) {
            // Multiple implementations of an interface, so assume the FetchPlan differs between implementation
            selectFetchPlan = false;
        }
        // TODO This only works if the different elementInfos have the same number of PK fields (otherwise get SQL error in UNION)
        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);
            iteratorMappingClass.setNucleusTypeColumnName(UnionStatementGenerator.DN_TYPE_COLUMN);
            SelectStatement subStmt = stmtGen.getStatement(ec);
            if (selectFetchPlan) {
                // Select the FetchPlan fields (of the element class)
                if (sqlStmt == null) {
                    SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(subStmt, iteratorMappingClass, fp, subStmt.getPrimaryTable(), elementInfo[i].getAbstractClassMetaData(), fp.getMaxFetchDepth());
                } else {
                    SQLStatementHelper.selectFetchPlanOfSourceClassInStatement(subStmt, null, fp, subStmt.getPrimaryTable(), elementInfo[i].getAbstractClassMetaData(), fp.getMaxFetchDepth());
                }
            } else {
                // Select the candidate id of the element class only
                if (sqlStmt == null) {
                    SQLStatementHelper.selectIdentityOfCandidateInStatement(subStmt, iteratorMappingClass, elementInfo[i].getAbstractClassMetaData());
                } else {
                    SQLStatementHelper.selectIdentityOfCandidateInStatement(subStmt, null, elementInfo[i].getAbstractClassMetaData());
                }
            }
            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 (orderMapping != null) {
        // Order by the ordering column, when present
        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);
    }
    return new IteratorStatement(this, sqlStmt, iteratorMappingClass);
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) 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) NucleusException(org.datanucleus.exceptions.NucleusException)

Aggregations

StatementClassMapping (org.datanucleus.store.rdbms.query.StatementClassMapping)30 StatementMappingIndex (org.datanucleus.store.rdbms.query.StatementMappingIndex)24 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)19 ExecutionContext (org.datanucleus.ExecutionContext)17 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)17 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)14 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)13 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)13 PreparedStatement (java.sql.PreparedStatement)12 SQLException (java.sql.SQLException)12 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)12 NucleusException (org.datanucleus.exceptions.NucleusException)12 ObjectProvider (org.datanucleus.state.ObjectProvider)12 ManagedConnection (org.datanucleus.store.connection.ManagedConnection)12 SQLController (org.datanucleus.store.rdbms.SQLController)12 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)12 UnionStatementGenerator (org.datanucleus.store.rdbms.sql.UnionStatementGenerator)10 ResultSet (java.sql.ResultSet)9 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)9 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)9