public NumberDataValue
getSetAutoincrementValue(int columnPosition, long increment)
throws StandardException
{
long startValue = 0;
NumberDataValue dvd;
int index = columnPosition - 1; // all our indices are 0 based.
/* As in DB2, only for single row insert: insert into t1(c1) values (..) do
* we return the correct most recently generated identity column value. For
* multiple row insert, or insert with sub-select, the return value is non-
* deterministic, and is the previous return value of the IDENTITY_VAL_LOCAL
* function, before the insert statement. Also, DB2 can have at most 1 identity
* column per table. The return value won't be affected either if Derby
* table has more than one identity columns.
*/
setIdentity = (! autoincrementGenerated) && isSourceRowResultSet();
autoincrementGenerated = true;
if (bulkInsert)
{
ColumnDescriptor cd = td.getColumnDescriptor(columnPosition);
long ret;
// for bulk insert we have the table descriptor
// System.out.println("in bulk insert");
if (aiCache[index].isNull())
{
if (bulkInsertReplace)
{
startValue = cd.getAutoincStart();
}
else
{
dvd = dd.getSetAutoincrementValue(
constants.autoincRowLocation[index],
tc, false, aiCache[index], true);
startValue = dvd.getLong();
}
lcc.autoincrementCreateCounter(td.getSchemaName(),
td.getName(),
cd.getColumnName(),
new Long(startValue),
increment,
columnPosition);
}
ret = lcc.nextAutoincrementValue(td.getSchemaName(),
td.getName(),
cd.getColumnName());
aiCache[columnPosition - 1].setValue(ret);
}
else
{
NumberDataValue newValue;
TransactionController nestedTC = null, tcToUse = tc;
try
{
// DERBY-5780, defaulting log syncing to false, which improves
// performance of identity value generation. If system
// crashes may reuse an identity value because commit did not
// sync, but only if no subsequent user transaction has
// committed or aborted and thus no row can exist that used
// the previous value. Without this identity values pay
// a synchronous I/O to the log file for each new value no
// matter how many are inserted in a single transaction.
nestedTC = tc.startNestedUserTransaction(false, false);
tcToUse = nestedTC;
}
catch (StandardException se)
{
// If I cannot start a Nested User Transaction use the parent
// transaction to do all the work.
tcToUse = tc;
}
try
{
/* If tcToUse == tc, then we are using parent xaction-- this
can happen if for some reason we couldn't start a nested
transaction
*/
newValue = dd.getSetAutoincrementValue(
constants.autoincRowLocation[index],
tcToUse, true, aiCache[index], (tcToUse == tc));
}
catch (StandardException se)
{
if (tcToUse == tc)
{
/* we've using the parent xaction and we've timed out; just
throw an error and exit.
*/
throw se;
}
if (se.getMessageId().equals(SQLState.LOCK_TIMEOUT))
{
// if we couldn't do this with a nested xaction, retry with
// parent-- we need to wait this time!
newValue = dd.getSetAutoincrementValue(
constants.autoincRowLocation[index],
tc, true, aiCache[index], true);
}
else if (se.getMessageId().equals(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE))
{
// if we got an overflow error, throw a more meaningful
// error message
throw StandardException.newException(
SQLState.LANG_AI_OVERFLOW,
se,
constants.getTableName(),
constants.getColumnName(index));
}
else throw se;
}
finally
{
// no matter what, commit the nested transaction; if something
// bad happened in the child xaction lets not abort the parent
// here.
if (nestedTC != null)
{
// DERBY-5493 - prior to fix all nested user update
// transactions did a nosync commit when commit() was
// called, this default has been changed to do synced
// commit. Changed this commit to be commitNoSync to
// not introduce performce degredation for autoincrement
// keys. As before, if server crashes the changes
// made in the nested transaction may be lost. If any
// subsequent user transaction is commited, including any
// inserts that would depend on the autoincrement value
// change then the nested tranaction is guaranteed on
// system crash.
nestedTC.commitNoSync(TransactionController.RELEASE_LOCKS);
nestedTC.destroy();
}
}
aiCache[index] = newValue;
if (setIdentity)
identityVal = newValue.getLong();
}
return aiCache[index];
}