Search in sources :

Example 1 with AbstractClassTable

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

the class InsertRequest method execute.

/**
 * Method performing the insertion of the record from the datastore.
 * Takes the constructed insert query and populates with the specific record information.
 * @param sm StateManager for the record to be inserted
 */
public void execute(DNStateManager sm) {
    ExecutionContext ec = sm.getExecutionContext();
    if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
        // Debug information about what we are inserting
        NucleusLogger.PERSISTENCE.debug(Localiser.msg("052207", sm.getObjectAsPrintable(), table));
    }
    try {
        VersionMetaData vermd = table.getVersionMetaData();
        RDBMSStoreManager storeMgr = table.getStoreManager();
        if (vermd != null && vermd.getMemberName() != null) {
            // Version field - Update the version in the object
            AbstractMemberMetaData verfmd = ((AbstractClassMetaData) vermd.getParent()).getMetaDataForMember(vermd.getMemberName());
            Object currentVersion = sm.getVersion();
            if (currentVersion instanceof Number) {
                // Cater for Integer based versions
                currentVersion = Long.valueOf(((Number) currentVersion).longValue());
            }
            Object nextOptimisticVersion = ec.getLockManager().getNextVersion(vermd, currentVersion);
            if (verfmd.getType() == Integer.class || verfmd.getType() == int.class) {
                // Cater for Integer based versions
                nextOptimisticVersion = Integer.valueOf(((Number) nextOptimisticVersion).intValue());
            }
            sm.replaceField(verfmd.getAbsoluteFieldNumber(), nextOptimisticVersion);
        }
        // Set the state to "inserting" (may already be at this state if multiple inheritance level INSERT)
        sm.setInserting();
        // sm.changeActivityState(ActivityState.INSERTING);
        SQLController sqlControl = storeMgr.getSQLController();
        ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
        try {
            List<String> pkColumnNames = new ArrayList<>();
            if (table.getIdentityType() == IdentityType.DATASTORE) {
                JavaTypeMapping mapping = table.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, true);
                ColumnMapping[] columnMappings = mapping.getColumnMappings();
                pkColumnNames = Stream.of(columnMappings).map(cm -> cm.getColumn().getIdentifier().getName()).collect(toList());
            } else if (table.getIdentityType() == IdentityType.APPLICATION) {
                List<Column> pkColumns = ((AbstractClassTable) table).getPrimaryKey().getColumns();
                if (!pkColumns.isEmpty()) {
                    pkColumnNames = pkColumns.stream().map(cm -> cm.getName()).collect(toList());
                }
            }
            PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, insertStmt, batch, hasIdentityColumn && storeMgr.getDatastoreAdapter().supportsOption(DatastoreAdapter.GET_GENERATED_KEYS_STATEMENT), pkColumnNames);
            try {
                StatementClassMapping mappingDefinition = new StatementClassMapping();
                for (int i = 0; i < stmtMappings.length; i++) {
                    if (stmtMappings[i] != null) {
                        mappingDefinition.addMappingForMember(i, stmtMappings[i]);
                    }
                }
                // Provide the primary key field(s)
                if (table.getIdentityType() == IdentityType.DATASTORE) {
                    if (!table.isObjectIdDatastoreAttributed() || !table.isBaseDatastoreClass()) {
                        int[] paramNumber = { IDPARAMNUMBER };
                        table.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false).setObject(ec, ps, paramNumber, sm.getInternalObjectId());
                    }
                } else if (table.getIdentityType() == IdentityType.APPLICATION) {
                    if (pkFieldNumbers != null && pkFieldNumbers.length > 0) {
                        sm.provideFields(pkFieldNumbers, new ParameterSetter(sm, ps, mappingDefinition));
                    }
                }
                // Provide all non-key fields needed for the insert - provides "persistence-by-reachability" for these fields
                if (insertFieldNumbers.length > 0) {
                    AbstractClassMetaData cmd = sm.getClassMetaData();
                    if (createTimestampStmtMapping != null) {
                        // Set create timestamp to time for the start of this transaction
                        int createTimestampMemberPos = cmd.getCreateTimestampMemberPosition();
                        AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(createTimestampMemberPos);
                        if (mmd.getType().isAssignableFrom(java.time.Instant.class)) {
                            sm.replaceField(createTimestampMemberPos, ec.getTransaction().getIsActive() ? java.time.Instant.ofEpochMilli(ec.getTransaction().getBeginTime()) : java.time.Instant.now());
                        } else {
                            sm.replaceField(createTimestampMemberPos, ec.getTransaction().getIsActive() ? new Timestamp(ec.getTransaction().getBeginTime()) : new Timestamp(System.currentTimeMillis()));
                        }
                    }
                    if (createUserStmtMapping != null) {
                        // Set create user to current user
                        sm.replaceField(cmd.getCreateUserMemberPosition(), ec.getCurrentUser());
                    }
                    int numberOfFieldsToProvide = 0;
                    int numMembers = cmd.getMemberCount();
                    for (int i = 0; i < insertFieldNumbers.length; i++) {
                        if (insertFieldNumbers[i] < numMembers) {
                            numberOfFieldsToProvide++;
                        }
                    }
                    int j = 0;
                    int[] fieldNums = new int[numberOfFieldsToProvide];
                    for (int i = 0; i < insertFieldNumbers.length; i++) {
                        if (insertFieldNumbers[i] < numMembers) {
                            fieldNums[j++] = insertFieldNumbers[i];
                        }
                    }
                    sm.provideFields(fieldNums, new ParameterSetter(sm, ps, mappingDefinition));
                }
                JavaTypeMapping versionMapping = table.getSurrogateMapping(SurrogateColumnType.VERSION, false);
                if (versionMapping != null) {
                    // Surrogate version - set the new version for the object
                    Object currentVersion = sm.getVersion();
                    Object nextOptimisticVersion = ec.getLockManager().getNextVersion(vermd, currentVersion);
                    for (int k = 0; k < versionStmtMapping.getNumberOfParameterOccurrences(); k++) {
                        versionMapping.setObject(ec, ps, versionStmtMapping.getParameterPositionsForOccurrence(k), nextOptimisticVersion);
                    }
                    sm.setTransactionalVersion(nextOptimisticVersion);
                } else if (vermd != null && vermd.getMemberName() != null) {
                    // Version field - set the new version for the object
                    Object currentVersion = sm.getVersion();
                    Object nextOptimisticVersion = ec.getLockManager().getNextVersion(vermd, currentVersion);
                    sm.setTransactionalVersion(nextOptimisticVersion);
                }
                if (multitenancyStmtMapping != null) {
                    // Multitenancy mapping
                    String tenantId = ec.getTenantId();
                    if (tenantId == null) {
                        NucleusLogger.PERSISTENCE.warn("Insert of object with multitenancy column but tenantId not set! Suggest that you set it.");
                    }
                    table.getSurrogateMapping(SurrogateColumnType.MULTITENANCY, false).setObject(ec, ps, multitenancyStmtMapping.getParameterPositionsForOccurrence(0), tenantId);
                }
                if (softDeleteStmtMapping != null) {
                    // Soft-Delete mapping
                    table.getSurrogateMapping(SurrogateColumnType.SOFTDELETE, false).setObject(ec, ps, softDeleteStmtMapping.getParameterPositionsForOccurrence(0), Boolean.FALSE);
                }
                if (createUserStmtMapping != null) {
                    table.getSurrogateMapping(SurrogateColumnType.CREATE_USER, false).setObject(ec, ps, createUserStmtMapping.getParameterPositionsForOccurrence(0), ec.getCurrentUser());
                }
                if (createTimestampStmtMapping != null) {
                    table.getSurrogateMapping(SurrogateColumnType.CREATE_TIMESTAMP, false).setObject(ec, ps, createTimestampStmtMapping.getParameterPositionsForOccurrence(0), new Timestamp(ec.getTransaction().getIsActive() ? ec.getTransaction().getBeginTime() : System.currentTimeMillis()));
                }
                if (updateUserStmtMapping != null) {
                    // TODO Do we need to specify this on INSERT? can they be nullable?
                    table.getSurrogateMapping(SurrogateColumnType.UPDATE_USER, false).setObject(ec, ps, updateUserStmtMapping.getParameterPositionsForOccurrence(0), "");
                }
                if (updateTimestampStmtMapping != null) {
                    // TODO Do we need to specify this on INSERT? can they be nullable?
                    table.getSurrogateMapping(SurrogateColumnType.UPDATE_TIMESTAMP, false).setObject(ec, ps, updateTimestampStmtMapping.getParameterPositionsForOccurrence(0), null);
                }
                JavaTypeMapping discrimMapping = table.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, false);
                if (discrimMapping != null) {
                    // Discriminator mapping
                    Object discVal = sm.getClassMetaData().getDiscriminatorValue();
                    for (int k = 0; k < discriminatorStmtMapping.getNumberOfParameterOccurrences(); k++) {
                        discrimMapping.setObject(ec, ps, discriminatorStmtMapping.getParameterPositionsForOccurrence(k), discVal);
                    }
                }
                // External FK columns (optional)
                if (externalFKStmtMappings != null) {
                    for (int i = 0; i < externalFKStmtMappings.length; i++) {
                        Object fkValue = sm.getAssociatedValue(externalFKStmtMappings[i].getMapping());
                        if (fkValue != null) {
                            // Need to provide the owner field number so PCMapping can work out if it is inserted yet
                            AbstractMemberMetaData ownerFmd = table.getMetaDataForExternalMapping(externalFKStmtMappings[i].getMapping(), MappingType.EXTERNAL_FK);
                            for (int k = 0; k < externalFKStmtMappings[i].getNumberOfParameterOccurrences(); k++) {
                                externalFKStmtMappings[i].getMapping().setObject(ec, ps, externalFKStmtMappings[i].getParameterPositionsForOccurrence(k), fkValue, null, ownerFmd.getAbsoluteFieldNumber());
                            }
                        } else {
                            // We're inserting a null so don't need the owner field
                            for (int k = 0; k < externalFKStmtMappings[i].getNumberOfParameterOccurrences(); k++) {
                                externalFKStmtMappings[i].getMapping().setObject(ec, ps, externalFKStmtMappings[i].getParameterPositionsForOccurrence(k), null);
                            }
                        }
                    }
                }
                // External FK discriminator columns (optional)
                if (externalFKDiscrimStmtMappings != null) {
                    for (int i = 0; i < externalFKDiscrimStmtMappings.length; i++) {
                        Object discrimValue = sm.getAssociatedValue(externalFKDiscrimStmtMappings[i].getMapping());
                        for (int k = 0; k < externalFKDiscrimStmtMappings[i].getNumberOfParameterOccurrences(); k++) {
                            externalFKDiscrimStmtMappings[i].getMapping().setObject(ec, ps, externalFKDiscrimStmtMappings[i].getParameterPositionsForOccurrence(k), discrimValue);
                        }
                    }
                }
                // External order columns (optional)
                if (externalOrderStmtMappings != null) {
                    for (int i = 0; i < externalOrderStmtMappings.length; i++) {
                        Object orderValue = sm.getAssociatedValue(externalOrderStmtMappings[i].getMapping());
                        if (orderValue == null) {
                            // No order value so use -1
                            orderValue = Integer.valueOf(-1);
                        }
                        for (int k = 0; k < externalOrderStmtMappings[i].getNumberOfParameterOccurrences(); k++) {
                            externalOrderStmtMappings[i].getMapping().setObject(ec, ps, externalOrderStmtMappings[i].getParameterPositionsForOccurrence(k), orderValue);
                        }
                    }
                }
                sqlControl.executeStatementUpdate(ec, mconn, insertStmt, ps, !batch);
                if (hasIdentityColumn) {
                    // Identity column was set in the datastore using auto-increment/identity/serial etc
                    Object newId = getInsertedIdentityValue(ec, sqlControl, sm, mconn, ps);
                    sm.setPostStoreNewObjectId(newId);
                    if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) {
                        NucleusLogger.DATASTORE_PERSIST.debug(Localiser.msg("052206", sm.getObjectAsPrintable(), IdentityUtils.getPersistableIdentityForId(sm.getInternalObjectId())));
                    }
                }
                // Execute any mapping actions on the insert of the fields (e.g Oracle CLOBs/BLOBs)
                if (postSetMappings != null) {
                    for (JavaTypeMapping m : postSetMappings) {
                        if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                            NucleusLogger.PERSISTENCE.debug(Localiser.msg("052222", sm.getObjectAsPrintable(), m.getMemberMetaData().getFullFieldName()));
                        }
                        m.performSetPostProcessing(sm);
                    }
                }
                // Update the insert status for this table via the StoreManager
                storeMgr.setObjectIsInsertedToLevel(sm, table);
                // (if we did it the other way around we would get a NotYetFlushedException thrown above).
                for (int i = 0; i < relationFieldNumbers.length; i++) {
                    Object value = sm.provideField(relationFieldNumbers[i]);
                    if (value != null && ec.getApiAdapter().isDetached(value)) {
                        Object valueAttached = ec.persistObjectInternal(value, null, -1, PersistableObjectType.PC);
                        sm.replaceField(relationFieldNumbers[i], valueAttached);
                    }
                }
                // Perform reachability on all fields that have no datastore column (1-1 bi non-owner, N-1 bi join)
                if (reachableFieldNumbers.length > 0) {
                    int numberOfReachableFields = 0;
                    for (int i = 0; i < reachableFieldNumbers.length; i++) {
                        if (reachableFieldNumbers[i] < sm.getClassMetaData().getMemberCount()) {
                            numberOfReachableFields++;
                        }
                    }
                    int[] fieldNums = new int[numberOfReachableFields];
                    int j = 0;
                    for (int i = 0; i < reachableFieldNumbers.length; i++) {
                        if (reachableFieldNumbers[i] < sm.getClassMetaData().getMemberCount()) {
                            fieldNums[j++] = reachableFieldNumbers[i];
                        }
                    }
                    mappingDefinition = new StatementClassMapping();
                    for (int i = 0; i < retrievedStmtMappings.length; i++) {
                        if (retrievedStmtMappings[i] != null) {
                            mappingDefinition.addMappingForMember(i, retrievedStmtMappings[i]);
                        }
                    }
                    NucleusLogger.PERSISTENCE.debug("Performing reachability on fields " + StringUtils.intArrayToString(fieldNums));
                    sm.provideFields(fieldNums, new ParameterSetter(sm, ps, mappingDefinition));
                }
            } finally {
                sqlControl.closeStatement(mconn, ps);
            }
        } finally {
            mconn.release();
        }
    } catch (SQLException e) {
        String msg = Localiser.msg("052208", sm.getObjectAsPrintable(), insertStmt, e.getMessage());
        NucleusLogger.DATASTORE_PERSIST.warn(msg);
        List<Exception> exceptions = new ArrayList<>();
        exceptions.add(e);
        while ((e = e.getNextException()) != null) {
            exceptions.add(e);
        }
        throw new NucleusDataStoreException(msg, exceptions.toArray(new Throwable[exceptions.size()]));
    }
    // Execute any mapping actions now that we have inserted the element (things like inserting any association parent-child).
    if (mappingCallbacks != null) {
        for (MappingCallbacks m : mappingCallbacks) {
            try {
                if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                    NucleusLogger.PERSISTENCE.debug(Localiser.msg("052209", IdentityUtils.getPersistableIdentityForId(sm.getInternalObjectId()), ((JavaTypeMapping) m).getMemberMetaData().getFullFieldName()));
                }
                m.postInsert(sm);
            } catch (NotYetFlushedException e) {
                sm.updateFieldAfterInsert(e.getPersistable(), ((JavaTypeMapping) m).getMemberMetaData().getAbsoluteFieldNumber());
            }
        }
    }
}
Also used : ParameterSetter(org.datanucleus.store.rdbms.fieldmanager.ParameterSetter) MappingConsumer(org.datanucleus.store.rdbms.mapping.MappingConsumer) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) SurrogateColumnType(org.datanucleus.store.schema.table.SurrogateColumnType) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) Localiser(org.datanucleus.util.Localiser) ColumnMapping(org.datanucleus.store.rdbms.mapping.column.ColumnMapping) ResultSet(java.sql.ResultSet) Map(java.util.Map) MetaData(org.datanucleus.metadata.MetaData) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) NucleusException(org.datanucleus.exceptions.NucleusException) Timestamp(java.sql.Timestamp) PreparedStatement(java.sql.PreparedStatement) SQLController(org.datanucleus.store.rdbms.SQLController) List(java.util.List) Stream(java.util.stream.Stream) IdentityUtils(org.datanucleus.identity.IdentityUtils) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) IdentityType(org.datanucleus.metadata.IdentityType) DNStateManager(org.datanucleus.state.DNStateManager) AbstractClassTable(org.datanucleus.store.rdbms.table.AbstractClassTable) PersistableObjectType(org.datanucleus.PersistableObjectType) StringUtils(org.datanucleus.util.StringUtils) MappingCallbacks(org.datanucleus.store.rdbms.mapping.MappingCallbacks) VersionMetaData(org.datanucleus.metadata.VersionMetaData) ExecutionContext(org.datanucleus.ExecutionContext) HashMap(java.util.HashMap) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) ArrayList(java.util.ArrayList) SQLException(java.sql.SQLException) NucleusLogger(org.datanucleus.util.NucleusLogger) MetaDataUtils(org.datanucleus.metadata.MetaDataUtils) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) Column(org.datanucleus.store.rdbms.table.Column) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) Iterator(java.util.Iterator) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) ColumnMetaData(org.datanucleus.metadata.ColumnMetaData) MappingType(org.datanucleus.store.rdbms.mapping.MappingType) Collectors.toList(java.util.stream.Collectors.toList) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) RelationType(org.datanucleus.metadata.RelationType) SecondaryTable(org.datanucleus.store.rdbms.table.SecondaryTable) NotYetFlushedException(org.datanucleus.exceptions.NotYetFlushedException) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) VersionMetaData(org.datanucleus.metadata.VersionMetaData) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SQLException(java.sql.SQLException) MappingCallbacks(org.datanucleus.store.rdbms.mapping.MappingCallbacks) ArrayList(java.util.ArrayList) ParameterSetter(org.datanucleus.store.rdbms.fieldmanager.ParameterSetter) Timestamp(java.sql.Timestamp) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) SQLController(org.datanucleus.store.rdbms.SQLController) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) List(java.util.List) ArrayList(java.util.ArrayList) Collectors.toList(java.util.stream.Collectors.toList) ColumnMapping(org.datanucleus.store.rdbms.mapping.column.ColumnMapping) 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) AbstractClassTable(org.datanucleus.store.rdbms.table.AbstractClassTable) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

PreparedStatement (java.sql.PreparedStatement)1 ResultSet (java.sql.ResultSet)1 SQLException (java.sql.SQLException)1 Timestamp (java.sql.Timestamp)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 Iterator (java.util.Iterator)1 List (java.util.List)1 Map (java.util.Map)1 Collectors.toList (java.util.stream.Collectors.toList)1 Stream (java.util.stream.Stream)1 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)1 ExecutionContext (org.datanucleus.ExecutionContext)1 PersistableObjectType (org.datanucleus.PersistableObjectType)1 NotYetFlushedException (org.datanucleus.exceptions.NotYetFlushedException)1 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)1 NucleusException (org.datanucleus.exceptions.NucleusException)1 IdentityUtils (org.datanucleus.identity.IdentityUtils)1 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)1 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)1