// Set the state to "inserting" (may already be at this state if multiple inheritance level INSERT)
sm.changeActivityState(ActivityState.INSERTING, table);
ObjectManager om = sm.getObjectManager();
RDBMSManager storeMgr = (RDBMSManager)om.getStoreManager();
SQLController sqlControl = storeMgr.getSQLController();
ManagedConnection mconn = storeMgr.getConnection(om);
try
{
PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, insertStmt, batch);
try
{
// Provide the primary key field(s)
if (table.getIdentityType() == IdentityType.DATASTORE)
{
if (!table.isObjectIDDatastoreAttributed() || !table.isBaseDatastoreClass())
{
int[] paramNumber = {IDPARAMNUMBER};
table.getDataStoreObjectIdMapping().setObject(om, ps, paramNumber, sm.getInternalObjectId());
}
}
else if (table.getIdentityType() == IdentityType.APPLICATION)
{
sm.provideFields(pkFieldNumbers, new ParameterSetter(sm, ps, statementExpressionIndex, true));
}
// Provide all non-key fields needed for the insert.
// This provides "persistence-by-reachability" for these fields
int numberOfFieldsToProvide = 0;
for (int i = 0; i < insertFieldNumbers.length; i++)
{
if (insertFieldNumbers[i] < sm.getHighestFieldNumber())
{
numberOfFieldsToProvide++;
}
}
int j = 0;
int[] classFieldNumbers = new int[numberOfFieldsToProvide];
for (int i = 0; i < insertFieldNumbers.length; i++)
{
if (insertFieldNumbers[i] < sm.getHighestFieldNumber())
{
classFieldNumbers[j++] = insertFieldNumbers[i];
}
else
{
// Any fields out of range for the class, we default or null.
// This happens when we insert a base class object
// and the sub-class is persisted to the same table ("superclass-table").
StatementExpressionIndex stmtExprIndex = statementExpressionIndex[insertFieldNumbers[i]];
stmtExprIndex.getMapping().setDefault(om, ps, stmtExprIndex.getParameterIndex());
}
}
sm.provideFields(classFieldNumbers, new ParameterSetter(sm, ps, statementExpressionIndex, true));
if (table.getVersionMapping(false) != null)
{
// Surrogate version - set the new version for the object
Object currentVersion = sm.getObjectManager().getApiAdapter().getVersion(sm);
Object nextOptimisticVersion = VersionMapping.getNextVersion(table.getVersionMetaData(),
currentVersion);
table.getVersionMapping(false).setObject(om, ps, versionStatementExpressionIndex.getParameterIndex(), nextOptimisticVersion);
sm.setTransactionalVersion(nextOptimisticVersion);
}
else if (vermd != null && vermd.getFieldName() != null)
{
// Version field - set the new version for the object
Object currentVersion = sm.getObjectManager().getApiAdapter().getVersion(sm);
Object nextOptimisticVersion = VersionMapping.getNextVersion(table.getVersionMetaData(),
currentVersion);
sm.setTransactionalVersion(nextOptimisticVersion);
}
// Discriminator mapping (optional)
if (table.getDiscriminatorMapping(false) != null)
{
DiscriminatorMetaData dismd = table.getDiscriminatorMetaData();
if (dismd.getStrategy() == DiscriminatorStrategy.CLASS_NAME)
{
table.getDiscriminatorMapping(false).setObject(om, ps, discriminatorStatementExpressionIndex.getParameterIndex(),
sm.getObject().getClass().getName());
}
else if (dismd.getStrategy() == DiscriminatorStrategy.VALUE_MAP)
{
// Use Discriminator info for the actual class
dismd = sm.getClassMetaData().getInheritanceMetaData().getDiscriminatorMetaData();
table.getDiscriminatorMapping(false).setObject(om, ps, discriminatorStatementExpressionIndex.getParameterIndex(), dismd.getValue());
}
}
// External FK columns (optional)
if (externalFKStatementExpressionIndex != null)
{
for (int i=0;i<externalFKStatementExpressionIndex.length;i++)
{
Object fkValue = sm.getValueForExternalField(externalFKStatementExpressionIndex[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(externalFKStatementExpressionIndex[i].getMapping(),
MappingConsumer.MAPPING_TYPE_EXTERNAL_FK);
externalFKStatementExpressionIndex[i].getMapping().setObject(om, ps,
externalFKStatementExpressionIndex[i].getParameterIndex(), fkValue, null, ownerFmd.getAbsoluteFieldNumber());
}
else
{
// We're inserting a null so dont need the owner field
externalFKStatementExpressionIndex[i].getMapping().setObject(om, ps,
externalFKStatementExpressionIndex[i].getParameterIndex(), null);
}
}
}
// External FK discriminator columns (optional)
if (externalFKDiscrimStatementExpressionIndex != null)
{
for (int i=0;i<externalFKDiscrimStatementExpressionIndex.length;i++)
{
Object discrimValue = sm.getValueForExternalField(externalFKDiscrimStatementExpressionIndex[i].getMapping());
externalFKDiscrimStatementExpressionIndex[i].getMapping().setObject(om, ps,
externalFKDiscrimStatementExpressionIndex[i].getParameterIndex(), discrimValue);
}
}
// External order columns (optional)
if (externalOrderStatementExpressionIndex != null)
{
for (int i=0;i<externalOrderStatementExpressionIndex.length;i++)
{
Object orderValue = sm.getValueForExternalField(externalOrderStatementExpressionIndex[i].getMapping());
if (orderValue == null)
{
// No order value so use -1
orderValue = new Integer(-1);
}
externalOrderStatementExpressionIndex[i].getMapping().setObject(om, ps,
externalOrderStatementExpressionIndex[i].getParameterIndex(), orderValue);
}
}
sqlControl.executeStatementUpdate(mconn, insertStmt, ps, !batch);
if (hasAutoIncrementColumn)
{
// Identity was set in the datastore using auto-increment/identity/serial etc
Object newId = getInsertedDatastoreIdentity(om, sqlControl, sm, mconn, ps);
if (JPOXLogger.DATASTORE_PERSIST.isDebugEnabled())
{
JPOXLogger.DATASTORE_PERSIST.debug(LOCALISER.msg("052206",
StringUtils.toJVMIDString(sm.getObject()), newId));
}
sm.setPostStoreNewObjectId(newId);
}
// Update the insert status for this table
sm.changeActivityState(ActivityState.INSERTING_CALLBACKS, table);
// Make sure all relation fields (1-1, N-1 with FK) we processed in the INSERT are attached.
// This is necessary because with a bidir relation and the other end attached we can just
// do the INSERT above first and THEN attach the other end here
// (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 && om.getApiAdapter().isDetached(value))
{
Object valueAttached = om.persistObjectInternal(value, null, null, -1, StateManager.PC);
sm.replaceField(relationFieldNumbers[i], valueAttached, false);
}
}
// Perform reachability on all fields that have no datastore column (1-1 bi non-owner, N-1 bi join)
int numberOfReachableFields = 0;
for (int i = 0; i < reachableFieldNumbers.length; i++)
{
if (reachableFieldNumbers[i] < sm.getHighestFieldNumber())
{
numberOfReachableFields++;
}
}
classFieldNumbers = new int[numberOfReachableFields];
j = 0;
for (int i = 0; i < reachableFieldNumbers.length; i++)
{
if (reachableFieldNumbers[i] < sm.getHighestFieldNumber())
{
classFieldNumbers[j++] = reachableFieldNumbers[i];
}
else
{
// Any fields out of range for the class, we default or null.
// This happens when we insert a base class object
// and the sub-class is persisted to the same table ("superclass-table").
StatementExpressionIndex stmtExprIndex = retrievedStatementExpressionIndex[reachableFieldNumbers[i]];
stmtExprIndex.getMapping().setDefault(om, ps, stmtExprIndex.getParameterIndex());
}
}
sm.provideFields(classFieldNumbers, new ParameterSetter(sm, ps, retrievedStatementExpressionIndex, true));
}
finally
{
sqlControl.closeStatement(mconn, ps);
}
}
finally
{
mconn.release();