You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2022/08/21 18:20:01 UTC
svn commit: r1903614 [5/6] - in /db/derby/code/branches/10.15: ./ java/org.apache.derby.engine/org/apache/derby/impl/sql/compile/ java/org.apache.derby.engine/org/apache/derby/impl/sql/execute/ java/org.apache.derby.tests/org/apache/derbyTesting/functi...
Modified: db/derby/code/branches/10.15/java/org.apache.derby.engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.15/java/org.apache.derby.engine/org/apache/derby/impl/sql/execute/InsertResultSet.java?rev=1903614&r1=1903613&r2=1903614&view=diff
==============================================================================
--- db/derby/code/branches/10.15/java/org.apache.derby.engine/org/apache/derby/impl/sql/execute/InsertResultSet.java (original)
+++ db/derby/code/branches/10.15/java/org.apache.derby.engine/org/apache/derby/impl/sql/execute/InsertResultSet.java Sun Aug 21 18:20:01 2022
@@ -87,155 +87,153 @@ import org.apache.derby.shared.common.sa
*/
class InsertResultSet extends DMLWriteGeneratedColumnsResultSet implements TargetResultSet
{
- // RESOLVE. Embarrassingly large public state. If we could move the
- // Replication code into the same package, then these variables
- // could be protected.
- // passed in at construction time
+ // RESOLVE. Embarrassingly large public state. If we could move the
+ // Replication code into the same package, then these variables
+ // could be protected.
+ // passed in at construction time
- NoPutResultSet savedSource;
- InsertConstantAction constants;
+ NoPutResultSet savedSource;
+ InsertConstantAction constants;
private GeneratedMethod generationClauses;
- private GeneratedMethod checkGM;
- private long heapConglom;
+ private GeneratedMethod checkGM;
+ private long heapConglom;
- // divined at run time
+ // divined at run time
- private RowChanger rowChanger;
+ private RowChanger rowChanger;
- private TransactionController tc;
- private ExecRow row;
+ private TransactionController tc;
+ private ExecRow row;
- boolean userSpecifiedBulkInsert;
- boolean bulkInsertPerformed;
+ boolean userSpecifiedBulkInsert;
+ boolean bulkInsertPerformed;
- // bulkInsert
- protected boolean bulkInsert;
- private boolean bulkInsertReplace;
- private boolean firstRow = true;
- private boolean[] needToDropSort;
-
- /*
- ** This hashtable is used to convert an index conglomerate
- ** from it's old conglom number to the new one. It is
- ** bulk insert specific.
- */
- private Hashtable<Long,Long> indexConversionTable;
-
- // indexedCols is 1-based
- private FormatableBitSet indexedCols;
- private ConglomerateController bulkHeapCC;
+ // bulkInsert
+ protected boolean bulkInsert;
+ private boolean bulkInsertReplace;
+ private boolean firstRow = true;
+ private boolean[] needToDropSort;
- protected DataDictionary dd;
- protected TableDescriptor td;
+ /*
+ ** This hashtable is used to convert an index conglomerate
+ ** from it's old conglom number to the new one. It is
+ ** bulk insert specific.
+ */
+ private Hashtable<Long,Long> indexConversionTable;
+
+ // indexedCols is 1-based
+ private FormatableBitSet indexedCols;
+ private ConglomerateController bulkHeapCC;
+
+ protected DataDictionary dd;
+ protected TableDescriptor td;
- private ExecIndexRow[] indexRows;
+ private ExecIndexRow[] indexRows;
private final int fullTemplateId;
private final String schemaName;
private final String tableName;
- private long[] sortIds;
- private RowLocationRetRowSource[]
- rowSources;
- private ScanController bulkHeapSC;
- private ColumnOrdering[][] ordering;
- private int[][] collation;
- private SortController[] sorters;
- private TemporaryRowHolderImpl rowHolder;
- private RowLocation rl;
-
- private boolean hasBeforeRowTrigger;
- private BulkTableScanResultSet tableScan;
-
- private int numOpens;
- private boolean firstExecute;
-
- // cached across open()s
- private FKInfo[] fkInfoArray;
- private TriggerInfo triggerInfo;
- private RISetChecker fkChecker;
- private TriggerEventActivator triggerActivator;
+ private long[] sortIds;
+ private RowLocationRetRowSource[]
+ rowSources;
+ private ScanController bulkHeapSC;
+ private ColumnOrdering[][] ordering;
+ private int[][] collation;
+ private SortController[] sorters;
+ private TemporaryRowHolderImpl rowHolder;
+ private RowLocation rl;
+
+ private boolean hasBeforeRowTrigger;
+ private BulkTableScanResultSet tableScan;
+
+ private int numOpens;
+ private boolean firstExecute;
+
+ // cached across open()s
+ private FKInfo[] fkInfoArray;
+ private TriggerInfo triggerInfo;
+ private RISetChecker fkChecker;
+ private TriggerEventActivator triggerActivator;
private BulkInsertCounter[] bulkInsertCounters;
private BackingStoreHashtable deferredChecks; // cached ref.
private List<UUID> violatingCheckConstraints;
- // TargetResultSet interface
+ // TargetResultSet interface
- /**
- * @see TargetResultSet#changedRow
- *
- * @exception StandardException thrown if cursor finish ed.
- */
- public void changedRow(ExecRow execRow, RowLocation rowLocation)
- throws StandardException
- {
- if (SanityManager.DEBUG)
- {
- SanityManager.ASSERT(bulkInsert,
- "bulkInsert exected to be true");
- }
-
- /* Set up sorters, etc. if 1st row and there are indexes */
- if (constants.irgs.length > 0)
- {
- RowLocation rlClone = (RowLocation) rowLocation.cloneValue(false);
-
- // Objectify any the streaming columns that are indexed.
- for (int i = 0; i < execRow.getRowArray().length; i++)
- {
- if (! constants.indexedCols[i])
- {
- continue;
- }
-
- if (execRow.getRowArray()[i] instanceof StreamStorable)
- ((DataValueDescriptor)execRow.getRowArray()[i]).getObject();
- }
-
- // Every index row will share the same row location, etc.
- if (firstRow)
- {
- firstRow = false;
- indexRows = new ExecIndexRow[constants.irgs.length];
- setUpAllSorts(execRow.getNewNullRow(), rlClone);
- }
-
- // Put the row into the indexes
- for (int index = 0; index < constants.irgs.length; index++)
- {
- // Get a new object Array for the index
- indexRows[index].getNewObjectArray();
- // Associate the index row with the source row
- constants.irgs[index].getIndexRow(execRow,
- rlClone,
- indexRows[index],
- (FormatableBitSet) null);
-
- // Insert the index row into the matching sorter
- sorters[index].insert(indexRows[index].getRowArray());
- }
- }
- }
+ /**
+ * @see TargetResultSet#changedRow
+ *
+ * @exception StandardException thrown if cursor finish ed.
+ */
+ public void changedRow(ExecRow execRow, RowLocation rowLocation)
+ throws StandardException {
+ if (SanityManager.DEBUG)
+ {
+ SanityManager.ASSERT(bulkInsert,
+ "bulkInsert exected to be true");
+ }
- /**
- * Preprocess the source row. Apply any check constraints here.
- * Do an inplace cloning of all key columns. For triggers, if
- * we have a before row trigger, we fire it here if we can.
- * This is useful for bulk insert where the store stands between
- * the source and us.
- *
- * @param execRow The source row.
- *
- * @return The preprocessed source row.
- * @exception StandardException thrown on error
- */
- public ExecRow preprocessSourceRow(ExecRow execRow)
- throws StandardException
- {
+ /* Set up sorters, etc. if 1st row and there are indexes */
+ if (constants.irgs.length > 0)
+ {
+ RowLocation rlClone = (RowLocation) rowLocation.cloneValue(false);
+
+ // Objectify any the streaming columns that are indexed.
+ for (int i = 0; i < execRow.getRowArray().length; i++)
+ {
+ if (! constants.indexedCols[i])
+ {
+ continue;
+ }
+
+ if (execRow.getRowArray()[i] instanceof StreamStorable)
+ ((DataValueDescriptor)execRow.getRowArray()[i]).getObject();
+ }
+
+ // Every index row will share the same row location, etc.
+ if (firstRow)
+ {
+ firstRow = false;
+ indexRows = new ExecIndexRow[constants.irgs.length];
+ setUpAllSorts(execRow.getNewNullRow(), rlClone);
+ }
+
+ // Put the row into the indexes
+ for (int index = 0; index < constants.irgs.length; index++)
+ {
+ // Get a new object Array for the index
+ indexRows[index].getNewObjectArray();
+ // Associate the index row with the source row
+ constants.irgs[index].getIndexRow(execRow,
+ rlClone,
+ indexRows[index],
+ (FormatableBitSet) null);
+
+ // Insert the index row into the matching sorter
+ sorters[index].insert(indexRows[index].getRowArray());
+ }
+ }
+ }
+
+ /**
+ * Preprocess the source row. Apply any check constraints here.
+ * Do an inplace cloning of all key columns. For triggers, if
+ * we have a before row trigger, we fire it here if we can.
+ * This is useful for bulk insert where the store stands between
+ * the source and us.
+ *
+ * @param execRow The source row.
+ *
+ * @return The preprocessed source row.
+ * @exception StandardException thrown on error
+ */
+ public ExecRow preprocessSourceRow(ExecRow execRow)
+ throws StandardException {
if (triggerInfo != null) {
// We do not use bulk insert if we have triggers
if (SanityManager.DEBUG) {
SanityManager.NOTREACHED();
}
- }
+ }
if ( generationClauses != null )
{
@@ -247,40 +245,40 @@ class InsertResultSet extends DMLWriteGe
if (!allOk) {
if (SanityManager.DEBUG) {
SanityManager.ASSERT(
- violatingCheckConstraints != null &&
- violatingCheckConstraints.size() > 0) ;
+ violatingCheckConstraints != null &&
+ violatingCheckConstraints.size() > 0) ;
}
// We will do a callback to remember this by
// offendingRowLocation called from HeapController#load
}
- }
- // RESOLVE - optimize the cloning
- if (constants.irgs.length > 0)
- {
- /* Do in-place cloning of all of the key columns */
- return execRow.getClone(indexedCols);
- }
- else
- {
- return execRow;
- }
- }
+ }
+ // RESOLVE - optimize the cloning
+ if (constants.irgs.length > 0)
+ {
+ /* Do in-place cloning of all of the key columns */
+ return execRow.getClone(indexedCols);
+ }
+ else
+ {
+ return execRow;
+ }
+ }
public void offendingRowLocation(RowLocation rl, long constainerId)
- throws StandardException {
+ throws StandardException {
if (violatingCheckConstraints != null) {
deferredChecks =
- DeferredConstraintsMemory.rememberCheckViolations(
- lcc,
- constants.targetUUID,
- schemaName,
- tableName,
- deferredChecks,
- violatingCheckConstraints,
- rl,
- new CheckInfo[1] /* dummy */);
+ DeferredConstraintsMemory.rememberCheckViolations(
+ lcc,
+ constants.targetUUID,
+ schemaName,
+ tableName,
+ deferredChecks,
+ violatingCheckConstraints,
+ rl,
+ new CheckInfo[1] /* dummy */);
violatingCheckConstraints.clear();
}
}
@@ -301,137 +299,135 @@ class InsertResultSet extends DMLWriteGe
// immediate, a check error will throw rather than return a false
// value.
SQLBoolean allOk =
- (SQLBoolean)checkGM.invoke(activation);
+ (SQLBoolean)checkGM.invoke(activation);
result = allOk.isNull() || allOk.getBoolean();
- }
+ }
return result;
- }
+ }
/*
* class interface
*
*/
/**
- *
- * @exception StandardException Thrown on error
+ *
+ * @exception StandardException Thrown on error
*/
InsertResultSet(NoPutResultSet source,
- GeneratedMethod generationClauses,
- GeneratedMethod checkGM,
- int fullTemplate,
- String schemaName,
- String tableName,
- Activation activation)
- throws StandardException
- {
- super(activation);
- sourceResultSet = source;
- constants = (InsertConstantAction) constantAction;
+ GeneratedMethod generationClauses,
+ GeneratedMethod checkGM,
+ int fullTemplate,
+ String schemaName,
+ String tableName,
+ Activation activation)
+ throws StandardException {
+ super(activation);
+ sourceResultSet = source;
+ constants = (InsertConstantAction) constantAction;
this.generationClauses = generationClauses;
- this.checkGM = checkGM;
+ this.checkGM = checkGM;
this.fullTemplateId = fullTemplate;
this.schemaName = schemaName;
this.tableName = tableName;
- heapConglom = constants.conglomId;
+ heapConglom = constants.conglomId;
identitySequenceUUIDString = constants.identitySequenceUUIDString;
tc = activation.getTransactionController();
- fkInfoArray = constants.getFKInfo();
- triggerInfo = constants.getTriggerInfo();
+ fkInfoArray = constants.getFKInfo();
+ triggerInfo = constants.getTriggerInfo();
- hasBeforeRowTrigger = (triggerInfo != null) ?
- triggerInfo.hasTrigger(true, true) :
- false;
+ hasBeforeRowTrigger = (triggerInfo != null) ?
+ triggerInfo.hasTrigger(true, true) :
+ false;
resultDescription = sourceResultSet.getResultDescription();
- // Is this a bulkInsert or regular insert?
- String insertMode = constants.getProperty("insertMode");
+ // Is this a bulkInsert or regular insert?
+ String insertMode = constants.getProperty("insertMode");
- initializeAIcache(constants.getAutoincRowLocation());
+ initializeAIcache(constants.getAutoincRowLocation());
- if (insertMode != null)
- {
- if (StringUtil.SQLEqualsIgnoreCase(insertMode,"BULKINSERT"))
- {
- userSpecifiedBulkInsert = true;
- }
- else if (StringUtil.SQLEqualsIgnoreCase(insertMode,"REPLACE"))
- {
- userSpecifiedBulkInsert = true;
- bulkInsertReplace = true;
- bulkInsert = true;
-
- /*
- ** For now, we don't allow bulk insert replace when
- ** there is a trigger.
- */
- if (triggerInfo != null)
- {
+ if (insertMode != null)
+ {
+ if (StringUtil.SQLEqualsIgnoreCase(insertMode,"BULKINSERT"))
+ {
+ userSpecifiedBulkInsert = true;
+ }
+ else if (StringUtil.SQLEqualsIgnoreCase(insertMode,"REPLACE"))
+ {
+ userSpecifiedBulkInsert = true;
+ bulkInsertReplace = true;
+ bulkInsert = true;
+
+ /*
+ ** For now, we don't allow bulk insert replace when
+ ** there is a trigger.
+ */
+ if (triggerInfo != null)
+ {
TriggerDescriptor trD = triggerInfo.getTriggerArray()[0];
throw StandardException.newException(
SQLState.LANG_NO_BULK_INSERT_REPLACE_WITH_TRIGGER_DURING_EXECUTION,
constants.getTableName(),
trD.getName());
- }
- }
- }
- }
+ }
+ }
+ }
+ }
- /**
- @exception StandardException Standard Derby error policy
- */
- public void open() throws StandardException
- {
- setup();
- // Remember if this is the 1st execution
- firstExecute = (rowChanger == null);
-
- autoincrementGenerated = false;
-
- dd = lcc.getDataDictionary();
-
- verifyAutoGeneratedRScolumnsList(constants.targetUUID);
-
- rowCount = 0L;
-
- if (numOpens++ == 0)
- {
- sourceResultSet.openCore();
- }
- else
- {
- sourceResultSet.reopenCore();
- }
-
- /* If the user specified bulkInsert (or replace) then we need
- * to get an exclusive table lock on the table. If it is a
- * regular bulk insert then we need to check to see if the
- * table is empty. (If not empty, then we end up doing a row
- * at a time insert.)
- */
- if (userSpecifiedBulkInsert)
- {
- if (! bulkInsertReplace)
- {
- bulkInsert = verifyBulkInsert();
- }
- else
- {
- getExclusiveTableLock();
- }
- }
-
- if (bulkInsert)
- {
- // Notify the source that we are the target
- sourceResultSet.setTargetResultSet(this);
+ /**
+ @exception StandardException Standard Derby error policy
+ */
+ public void open() throws StandardException {
+ setup();
+ // Remember if this is the 1st execution
+ firstExecute = (rowChanger == null);
+
+ autoincrementGenerated = false;
+
+ dd = lcc.getDataDictionary();
+
+ verifyAutoGeneratedRScolumnsList(constants.targetUUID);
+
+ rowCount = 0L;
+
+ if (numOpens++ == 0)
+ {
+ sourceResultSet.openCore();
+ }
+ else
+ {
+ sourceResultSet.reopenCore();
+ }
+
+ /* If the user specified bulkInsert (or replace) then we need
+ * to get an exclusive table lock on the table. If it is a
+ * regular bulk insert then we need to check to see if the
+ * table is empty. (If not empty, then we end up doing a row
+ * at a time insert.)
+ */
+ if (userSpecifiedBulkInsert)
+ {
+ if (! bulkInsertReplace)
+ {
+ bulkInsert = verifyBulkInsert();
+ }
+ else
+ {
+ getExclusiveTableLock();
+ }
+ }
+
+ if (bulkInsert)
+ {
+ // Notify the source that we are the target
+ sourceResultSet.setTargetResultSet(this);
ExecRow fullTemplate =
((ExecRowBuilder) activation.getPreparedStatement().
- getSavedObject(fullTemplateId)).build(
- activation.getExecutionFactory());
+ getSavedObject(fullTemplateId)).build(
+ activation.getExecutionFactory());
bulkInsertCore(lcc, fullTemplate, heapConglom);
@@ -440,108 +436,106 @@ class InsertResultSet extends DMLWriteGe
// If we have triggers, we do not use bulkInsert
SanityManager.NOTREACHED();
}
- }
+ }
bulkValidateForeignKeys(tc, lcc.getContextManager(), fullTemplate);
- bulkInsertPerformed = true;
- }
- else
- {
- row = getNextRowCore(sourceResultSet);
- normalInsertCore(lcc, firstExecute);
- }
-
- /* Cache query plan text for source, before it gets blown away */
- if (lcc.getRunTimeStatisticsMode())
- {
- /* savedSource nulled after run time statistics generation */
- savedSource = sourceResultSet;
- }
+ bulkInsertPerformed = true;
+ }
+ else
+ {
+ row = getNextRowCore(sourceResultSet);
+ normalInsertCore(lcc, firstExecute);
+ }
- cleanUp();
+ /* Cache query plan text for source, before it gets blown away */
+ if (lcc.getRunTimeStatisticsMode())
+ {
+ /* savedSource nulled after run time statistics generation */
+ savedSource = sourceResultSet;
+ }
- saveAIcacheInformation(constants.getSchemaName(),
- constants.getTableName(), constants.getColumnNames());
+ cleanUp();
- endTime = getCurrentTimeMillis();
- }
+ saveAIcacheInformation(constants.getSchemaName(),
+ constants.getTableName(), constants.getColumnNames());
- /**
- * Clean up resources and call close on data members.
- */
- public void close() throws StandardException {
- close( constants.underMerge() );
- if (autoGeneratedKeysRowsHolder != null) {
- autoGeneratedKeysRowsHolder.close();
- }
- }
+ endTime = getCurrentTimeMillis();
+ }
- /**
- * If user didn't provide columns list for auto-generated columns, then only include
- * columns with auto-generated values in the resultset. Those columns would be ones
- * with default value defined.
- */
- private int[] generatedColumnPositionsArray()
- throws StandardException
- {
+ /**
+ * Clean up resources and call close on data members.
+ */
+ public void close() throws StandardException {
+ close( constants.underMerge() );
+ if (autoGeneratedKeysRowsHolder != null) {
+ autoGeneratedKeysRowsHolder.close();
+ }
+ }
+
+ /**
+ * If user didn't provide columns list for auto-generated columns, then only include
+ * columns with auto-generated values in the resultset. Those columns would be ones
+ * with default value defined.
+ */
+ private int[] generatedColumnPositionsArray()
+ throws StandardException {
TableDescriptor tabDesb = dd.getTableDescriptor(constants.targetUUID);
- ColumnDescriptor cd;
+ ColumnDescriptor cd;
int size = tabDesb.getMaxColumnID();
- int[] generatedColumnPositionsArray = new int[size];
+ int[] generatedColumnPositionsArray = new int[size];
Arrays.fill(generatedColumnPositionsArray, -1);
- int generatedColumnNumbers = 0;
+ int generatedColumnNumbers = 0;
- for (int i=0; i<size; i++) {
+ for (int i=0; i<size; i++) {
cd = tabDesb.getColumnDescriptor(i+1);
- if (cd.isAutoincrement()) { //if the column has auto-increment value
- generatedColumnNumbers++;
- generatedColumnPositionsArray[i] = i+1;
- } else if (cd.getDefaultValue() != null || cd.getDefaultInfo() != null) {//default value
- generatedColumnNumbers++;
- generatedColumnPositionsArray[i] = i+1;
- }
- }
- int[] returnGeneratedColumnPositionsArray = new int[generatedColumnNumbers];
-
- for (int i=0, j=0; i<size; i++) {
- if (generatedColumnPositionsArray[i] != -1)
- returnGeneratedColumnPositionsArray[j++] = generatedColumnPositionsArray[i];
- }
+ if (cd.isAutoincrement()) { //if the column has auto-increment value
+ generatedColumnNumbers++;
+ generatedColumnPositionsArray[i] = i+1;
+ } else if (cd.getDefaultValue() != null || cd.getDefaultInfo() != null) {//default value
+ generatedColumnNumbers++;
+ generatedColumnPositionsArray[i] = i+1;
+ }
+ }
+ int[] returnGeneratedColumnPositionsArray = new int[generatedColumnNumbers];
- return returnGeneratedColumnPositionsArray;
- }
+ for (int i=0, j=0; i<size; i++) {
+ if (generatedColumnPositionsArray[i] != -1)
+ returnGeneratedColumnPositionsArray[j++] = generatedColumnPositionsArray[i];
+ }
- /**
- * getSetAutoincrementValue will get the autoincrement value of the
- * columnPosition specified for the target table. If increment is
- * non-zero we will also update the autoincrement value.
- *
- * @param columnPosition position of the column in the table (1-based)
- * @param increment amount of increment.
- *
- * @exception StandardException if anything goes wrong.
- */
- public NumberDataValue
- getSetAutoincrementValue(int columnPosition, long increment)
- throws StandardException
- {
- int index = columnPosition - 1; // all our indices are 0 based.
+ return returnGeneratedColumnPositionsArray;
+ }
- /* 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;
+ /**
+ * getSetAutoincrementValue will get the autoincrement value of the
+ * columnPosition specified for the target table. If increment is
+ * non-zero we will also update the autoincrement value.
+ *
+ * @param columnPosition position of the column in the table (1-based)
+ * @param increment amount of increment.
+ *
+ * @exception StandardException if anything goes wrong.
+ */
+ public NumberDataValue
+ getSetAutoincrementValue(int columnPosition, long increment)
+ throws StandardException {
+ 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)
- {
+ if (bulkInsert)
+ {
if ( identitySequenceUUIDString == null )
{
getOldStyleBulkInsertValue( index, increment );
@@ -554,10 +548,10 @@ class InsertResultSet extends DMLWriteGe
}
bulkInsertCounters[ index ].getCurrentValueAndAdvance( (NumberDataValue) aiCache[ index ] );
}
- }
- else
- {
- NumberDataValue newValue;
+ }
+ else
+ {
+ NumberDataValue newValue;
//
// If there is a sequence generator uuid, then the database is at level
@@ -574,308 +568,304 @@ class InsertResultSet extends DMLWriteGe
( identitySequenceUUIDString, aiCache[ index ].getTypeFormatId() );
}
- aiCache[index] = newValue;
- if (setIdentity)
+ aiCache[index] = newValue;
+ if (setIdentity)
{
- identityVal = newValue.getLong();
+ identityVal = newValue.getLong();
}
- }
+ }
- return (NumberDataValue) aiCache[index];
- }
+ return (NumberDataValue) aiCache[index];
+ }
- /**
- * Identity generation logic for bulk-insert used in pre-10.11 databases.
- *
- * @param index 0-based index into aiCache
- */
- private void getOldStyleBulkInsertValue( int index, long increment )
- throws StandardException
- {
- NumberDataValue dvd;
- int columnPosition = index + 1;
- ColumnDescriptor cd = td.getColumnDescriptor(columnPosition);
- long ret;
+ /**
+ * Identity generation logic for bulk-insert used in pre-10.11 databases.
+ *
+ * @param index 0-based index into aiCache
+ */
+ private void getOldStyleBulkInsertValue( int index, long increment )
+ throws StandardException {
+ NumberDataValue dvd;
+ int columnPosition = index + 1;
+ 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())
- {
- long startValue;
+ // for bulk insert we have the table descriptor
+ // System.out.println("in bulk insert");
+ if (aiCache[index].isNull())
+ {
+ long startValue;
- if (bulkInsertReplace)
- {
- startValue = cd.getAutoincStart();
- }
- else
- {
- dvd = dd.getSetAutoincrementValue(
- constants.autoincRowLocation[index],
- tc, false, (NumberDataValue) aiCache[index], true);
- startValue = dvd.getLong();
- }
- lcc.autoincrementCreateCounter(td.getSchemaName(),
- td.getName(),
- cd.getColumnName(),
- Long.valueOf(startValue),
- increment,
- columnPosition);
+ if (bulkInsertReplace)
+ {
+ startValue = cd.getAutoincStart();
+ }
+ else
+ {
+ dvd = dd.getSetAutoincrementValue(
+ constants.autoincRowLocation[index],
+ tc, false, (NumberDataValue) aiCache[index], true);
+ startValue = dvd.getLong();
+ }
+ lcc.autoincrementCreateCounter(td.getSchemaName(),
+ td.getName(),
+ cd.getColumnName(),
+ Long.valueOf(startValue),
+ increment,
+ columnPosition);
- }
- ret = lcc.nextAutoincrementValue(td.getSchemaName(),
- td.getName(),
- cd.getColumnName());
- aiCache[columnPosition - 1].setValue(ret);
- }
+ }
+ ret = lcc.nextAutoincrementValue(td.getSchemaName(),
+ td.getName(),
+ cd.getColumnName());
+ aiCache[columnPosition - 1].setValue(ret);
+ }
- /**
- * Identity generation logic used in pre-10.11 databases.
- *
- * @param index 0-based index into aiCache
- */
- private NumberDataValue getOldStyleIdentityValue( int index )
- throws StandardException
- {
- NumberDataValue newValue;
- TransactionController nestedTC = null;
- TransactionController tcToUse;
+ /**
+ * Identity generation logic used in pre-10.11 databases.
+ *
+ * @param index 0-based index into aiCache
+ */
+ private NumberDataValue getOldStyleIdentityValue( int index )
+ throws StandardException {
+ NumberDataValue newValue;
+ TransactionController nestedTC = null;
+ TransactionController tcToUse;
- 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
+ {
+ // 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, (NumberDataValue) 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;
- }
+ 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, (NumberDataValue) 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) || se.isSelfDeadlock() )
- {
- // 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, (NumberDataValue) 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 ( se.getMessageId().equals(SQLState.LOCK_TIMEOUT) || se.isSelfDeadlock() )
+ {
+ // 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, (NumberDataValue) 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();
- }
- }
+ 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();
+ }
+ }
- return newValue;
- }
+ return newValue;
+ }
- // Is sourceResultSet a RowResultSet (values clause)?
- private boolean isSourceRowResultSet ()
+ // Is sourceResultSet a RowResultSet (values clause)?
+ private boolean isSourceRowResultSet ()
{
- boolean isRow = false;
- if (sourceResultSet instanceof NormalizeResultSet)
- isRow = (((NormalizeResultSet) sourceResultSet).source instanceof RowResultSet);
- return isRow;
+ boolean isRow = false;
+ if (sourceResultSet instanceof NormalizeResultSet)
+ isRow = (((NormalizeResultSet) sourceResultSet).source instanceof RowResultSet);
+ return isRow;
}
// checks if source result set is a RowResultSet type.
- private boolean isSingleRowResultSet()
- {
+ private boolean isSingleRowResultSet() {
boolean isRow = false;
if (sourceResultSet instanceof RowResultSet)
- isRow = true;
+ isRow = true;
else if (sourceResultSet instanceof NormalizeResultSet)
isRow = (((NormalizeResultSet) sourceResultSet).source instanceof RowResultSet);
return isRow;
}
- // Do the work for a "normal" insert
- private void normalInsertCore(LanguageConnectionContext lcc, boolean firstExecute)
- throws StandardException
- {
- boolean setUserIdentity = constants.hasAutoincrement() && isSingleRowResultSet();
+ // Do the work for a "normal" insert
+ private void normalInsertCore(LanguageConnectionContext lcc, boolean firstExecute)
+ throws StandardException {
+ boolean setUserIdentity = constants.hasAutoincrement() && isSingleRowResultSet();
ExecRow deferredRowBuffer;
long user_autoinc=0;
- /* Get or re-use the row changer.
- */
- if (firstExecute)
- {
- rowChanger = lcc.getLanguageConnectionFactory().getExecutionFactory()
- .getRowChanger(
- heapConglom,
- constants.heapSCOCI,
- heapDCOCI,
- constants.irgs,
- constants.indexCIDS,
- constants.indexSCOCIs,
- indexDCOCIs,
- 0, // number of columns in partial row meaningless for insert
- tc,
- null, //Changed column ids
- constants.getStreamStorableHeapColIds(),
- activation
- );
- rowChanger.setIndexNames(constants.indexNames);
- }
-
- /* decode lock mode for the execution isolation level */
- int lockMode = decodeLockMode(constants.lockMode);
-
- rowChanger.open(lockMode);
-
- /* The source does not know whether or not we are doing a
- * deferred mode insert. If we are, then we must clear the
- * index scan info from the activation so that the row changer
- * does not re-use that information (which won't be valid for
- * a deferred mode insert).
- */
- if (constants.deferred)
- {
- activation.clearIndexScanInfo();
- }
-
- if (fkInfoArray != null)
- {
- if (fkChecker == null)
- {
+ /* Get or re-use the row changer.
+ */
+ if (firstExecute)
+ {
+ rowChanger = lcc.getLanguageConnectionFactory().getExecutionFactory()
+ .getRowChanger(
+ heapConglom,
+ constants.heapSCOCI,
+ heapDCOCI,
+ constants.irgs,
+ constants.indexCIDS,
+ constants.indexSCOCIs,
+ indexDCOCIs,
+ 0, // number of columns in partial row meaningless for insert
+ tc,
+ null, //Changed column ids
+ constants.getStreamStorableHeapColIds(),
+ activation
+ );
+ rowChanger.setIndexNames(constants.indexNames);
+ }
+
+ /* decode lock mode for the execution isolation level */
+ int lockMode = decodeLockMode(constants.lockMode);
+
+ rowChanger.open(lockMode);
+
+ /* The source does not know whether or not we are doing a
+ * deferred mode insert. If we are, then we must clear the
+ * index scan info from the activation so that the row changer
+ * does not re-use that information (which won't be valid for
+ * a deferred mode insert).
+ */
+ if (constants.deferred)
+ {
+ activation.clearIndexScanInfo();
+ }
+
+ if (fkInfoArray != null)
+ {
+ if (fkChecker == null)
+ {
fkChecker = new RISetChecker(lcc, tc, fkInfoArray);
- }
- else
- {
- fkChecker.reopen();
- }
- }
-
- if (firstExecute && constants.deferred)
- {
- Properties properties = new Properties();
-
- // Get the properties on the old heap
- rowChanger.getHeapConglomerateController().getInternalTablePropertySet(properties);
-
- /*
- ** If deferred we save a copy of the entire row.
- */
- rowHolder = new TemporaryRowHolderImpl(activation, properties,
- resultDescription);
- rowChanger.setRowHolder(rowHolder);
- }
+ }
+ else
+ {
+ fkChecker.reopen();
+ }
+ }
- firstExecuteSpecialHandlingAutoGen(firstExecute, rowChanger, constants.targetUUID);
+ if (firstExecute && constants.deferred)
+ {
+ Properties properties = new Properties();
+
+ // Get the properties on the old heap
+ rowChanger.getHeapConglomerateController().getInternalTablePropertySet(properties);
+
+ /*
+ ** If deferred we save a copy of the entire row.
+ */
+ rowHolder = new TemporaryRowHolderImpl(activation, properties,
+ resultDescription);
+ rowChanger.setRowHolder(rowHolder);
+ }
- while ( row != null )
- {
+ firstExecuteSpecialHandlingAutoGen(firstExecute, rowChanger, constants.targetUUID);
+
+ while ( row != null )
+ {
// Collect auto-generated keys if requested.
// DERBY-5823: No need to collect them if there are no
// auto-generated key columns.
if (activation.getAutoGeneratedKeysResultsetMode() &&
- autoGeneratedKeysColumnIndexes.length > 0) {
+ autoGeneratedKeysColumnIndexes.length > 0) {
autoGeneratedKeysRowsHolder.insert(
- getCompactRow(row, autoGeneratedKeysColumnIndexes));
+ getCompactRow(row, autoGeneratedKeysColumnIndexes));
}
// fill in columns that are computed from expressions on other columns
evaluateGenerationClauses( generationClauses, activation, sourceResultSet, row, false );
- /*
- ** If we're doing a deferred insert, insert into the temporary
- ** conglomerate. Otherwise, insert directly into the permanent
- ** conglomerates using the rowChanger.
- */
- if (constants.deferred)
- {
- rowHolder.insert(row);
- }
- else
- {
+ /*
+ ** If we're doing a deferred insert, insert into the temporary
+ ** conglomerate. Otherwise, insert directly into the permanent
+ ** conglomerates using the rowChanger.
+ */
+ if (constants.deferred)
+ {
+ rowHolder.insert(row);
+ }
+ else
+ {
// Immediate mode violations will throw, so we only ever
// see false here with deferred constraint mode for one or more
// of the constraints being checked.
boolean allOk = evaluateCheckConstraints();
- if (fkChecker != null)
- {
+ if (fkChecker != null)
+ {
fkChecker.doFKCheck(activation, row);
- }
+ }
+
+ // Objectify any streaming columns that are indexed.
+ if (constants.irgs.length > 0)
+ {
+ DataValueDescriptor[] rowArray = row.getRowArray();
+ for (int i = 0; i < rowArray.length; i++)
+ {
+ //System.out.println("checking " + i);
+ if (! constants.indexedCols[i])
+ {
+ continue;
+ }
- // Objectify any streaming columns that are indexed.
- if (constants.irgs.length > 0)
- {
- DataValueDescriptor[] rowArray = row.getRowArray();
- for (int i = 0; i < rowArray.length; i++)
- {
- //System.out.println("checking " + i);
- if (! constants.indexedCols[i])
- {
- continue;
- }
-
-
- if (rowArray[i] instanceof StreamStorable)
- rowArray[i].getObject();
- }
- }
+
+ if (rowArray[i] instanceof StreamStorable)
+ rowArray[i].getObject();
+ }
+ }
if (allOk) {
rowChanger.insertRow(row, false);
@@ -892,110 +882,110 @@ class InsertResultSet extends DMLWriteGe
offendingRow,
new CheckInfo[1] /* dummy */);
}
- }
+ }
rowCount++;
if(setUserIdentity )
{
- dd = lcc.getDataDictionary();
- td = dd.getTableDescriptor(constants.targetUUID);
+ dd = lcc.getDataDictionary();
+ td = dd.getTableDescriptor(constants.targetUUID);
- int maxColumns = td.getMaxColumnID();
- int col;
+ int maxColumns = td.getMaxColumnID();
+ int col;
- for(col=1;col<=maxColumns;col++)
- {
- ColumnDescriptor cd = td.getColumnDescriptor(col);
- if(cd.isAutoincrement())
- {
- break;
- }
- }
+ for(col=1;col<=maxColumns;col++)
+ {
+ ColumnDescriptor cd = td.getColumnDescriptor(col);
+ if(cd.isAutoincrement())
+ {
+ break;
+ }
+ }
- if(col <= maxColumns)
- {
- DataValueDescriptor dvd = row.cloneColumn(col);
- user_autoinc = dvd.getLong();
- }
- }
+ if(col <= maxColumns)
+ {
+ DataValueDescriptor dvd = row.cloneColumn(col);
+ user_autoinc = dvd.getLong();
+ }
+ }
- // No need to do a next on a single row source
- if (constants.singleRowSource)
- {
- row = null;
- }
- else
- {
+ // No need to do a next on a single row source
+ if (constants.singleRowSource)
+ {
+ row = null;
+ }
+ else
+ {
row = getNextRowCore(sourceResultSet);
- }
+ }
}
- /*
- ** If it's a deferred insert, scan the temporary conglomerate and
- ** insert the rows into the permanent conglomerates using rowChanger.
- */
- if (constants.deferred)
- {
- if (triggerInfo != null)
- {
- Vector<AutoincrementCounter> v = null;
- if (aiCache != null)
- {
- v = new Vector<AutoincrementCounter>();
- for (int i = 0; i < aiCache.length; i++)
- {
- String s, t, c;
- if (aiCache[i] == null)
- continue;
+ /*
+ ** If it's a deferred insert, scan the temporary conglomerate and
+ ** insert the rows into the permanent conglomerates using rowChanger.
+ */
+ if (constants.deferred)
+ {
+ if (triggerInfo != null)
+ {
+ Vector<AutoincrementCounter> v = null;
+ if (aiCache != null)
+ {
+ v = new Vector<AutoincrementCounter>();
+ for (int i = 0; i < aiCache.length; i++)
+ {
+ String s, t, c;
+ if (aiCache[i] == null)
+ continue;
- Long initialValue =
- lcc.lastAutoincrementValue(
- (s = constants.getSchemaName()),
- (t = constants.getTableName()),
- (c = constants.getColumnName(i)));
-
-
- AutoincrementCounter aic =
- new AutoincrementCounter(
- initialValue,
- constants.getAutoincIncrement(i),
- aiCache[i].getLong(),
- s, t, c, i + 1);
- v.addElement(aic);
- }
- }
-
- if (triggerActivator == null)
- {
- triggerActivator = new TriggerEventActivator(lcc,
- constants.targetUUID,
- triggerInfo,
- TriggerExecutionContext.INSERT_EVENT,
- activation,
- v);
- }
- else
- {
- triggerActivator.reopen();
- }
-
- // fire BEFORE trigger, do this before checking constraints
- triggerActivator.notifyEvent(TriggerEvents.BEFORE_INSERT,
- (CursorResultSet)null,
- rowHolder.getResultSet(),
- (int[])null);
- }
-
- CursorResultSet rs = rowHolder.getResultSet();
- try
- {
- rs.open();
- while ((deferredRowBuffer = rs.getNextRow()) != null)
- {
- // we have to set the source row so the check constraint
- // sees the correct row.
- sourceResultSet.setCurrentRow(deferredRowBuffer);
+ Long initialValue =
+ lcc.lastAutoincrementValue(
+ (s = constants.getSchemaName()),
+ (t = constants.getTableName()),
+ (c = constants.getColumnName(i)));
+
+
+ AutoincrementCounter aic =
+ new AutoincrementCounter(
+ initialValue,
+ constants.getAutoincIncrement(i),
+ aiCache[i].getLong(),
+ s, t, c, i + 1);
+ v.addElement(aic);
+ }
+ }
+
+ if (triggerActivator == null)
+ {
+ triggerActivator = new TriggerEventActivator(lcc,
+ constants.targetUUID,
+ triggerInfo,
+ TriggerExecutionContext.INSERT_EVENT,
+ activation,
+ v);
+ }
+ else
+ {
+ triggerActivator.reopen();
+ }
+
+ // fire BEFORE trigger, do this before checking constraints
+ triggerActivator.notifyEvent(TriggerEvents.BEFORE_INSERT,
+ (CursorResultSet)null,
+ rowHolder.getResultSet(),
+ (int[])null);
+ }
+
+ CursorResultSet rs = rowHolder.getResultSet();
+ try
+ {
+ rs.open();
+ while ((deferredRowBuffer = rs.getNextRow()) != null)
+ {
+ // we have to set the source row so the check constraint
+ // sees the correct row.
+ sourceResultSet.setCurrentRow(deferredRowBuffer);
boolean allOk = evaluateCheckConstraints();
if (allOk) {
@@ -1014,71 +1004,70 @@ class InsertResultSet extends DMLWriteGe
offendingRow,
new CheckInfo[1]);
}
- }
- } finally
- {
- sourceResultSet.clearCurrentRow();
- rs.close();
- }
+ }
+ } finally
+ {
+ sourceResultSet.clearCurrentRow();
+ rs.close();
+ }
- if (fkChecker != null)
- {
- /*
- ** Second scan to make sure all the foreign key
- ** constraints are ok. We have to do this after
- ** we have completed the inserts in case of self
- ** referencing constraints.
- */
- rs = rowHolder.getResultSet();
- try
- {
- rs.open();
- while ((deferredRowBuffer = rs.getNextRow()) != null)
- {
- fkChecker.doFKCheck(activation, deferredRowBuffer);
- }
- } finally
- {
- rs.close();
- }
- }
-
- // fire AFTER trigger
- if (triggerActivator != null)
- {
- triggerActivator.notifyEvent(TriggerEvents.AFTER_INSERT,
- (CursorResultSet)null,
- rowHolder.getResultSet(),
- (int[])null);
- }
- }
-
- if (rowHolder != null)
- {
- rowHolder.close();
- // rowHolder kept across opens
- }
- if (fkChecker != null)
- {
- fkChecker.close();
- fkChecker = null;
- }
- if (setIdentity)
- lcc.setIdentityValue(identityVal);
+ if (fkChecker != null)
+ {
/*
- * find the value of the identity column from the user inserted value
- * and do a lcc.setIdentityValue(<user_value>);
- */
- else if(setUserIdentity )
- {
- lcc.setIdentityValue(user_autoinc);
- }
- }
+ ** Second scan to make sure all the foreign key
+ ** constraints are ok. We have to do this after
+ ** we have completed the inserts in case of self
+ ** referencing constraints.
+ */
+ rs = rowHolder.getResultSet();
+ try
+ {
+ rs.open();
+ while ((deferredRowBuffer = rs.getNextRow()) != null)
+ {
+ fkChecker.doFKCheck(activation, deferredRowBuffer);
+ }
+ } finally
+ {
+ rs.close();
+ }
+ }
+
+ // fire AFTER trigger
+ if (triggerActivator != null)
+ {
+ triggerActivator.notifyEvent(TriggerEvents.AFTER_INSERT,
+ (CursorResultSet)null,
+ rowHolder.getResultSet(),
+ (int[])null);
+ }
+ }
+
+ if (rowHolder != null)
+ {
+ rowHolder.close();
+ // rowHolder kept across opens
+ }
+ if (fkChecker != null)
+ {
+ fkChecker.close();
+ fkChecker = null;
+ }
+ if (setIdentity)
+ lcc.setIdentityValue(identityVal);
+ /*
+ * find the value of the identity column from the user inserted value
+ * and do a lcc.setIdentityValue(<user_value>);
+ */
+ else if(setUserIdentity )
+ {
+ lcc.setIdentityValue(user_autoinc);
+ }
+ }
@Override
- protected ExecRow getNextRowCore( NoPutResultSet source )
- throws StandardException
- {
+ protected ExecRow getNextRowCore( NoPutResultSet source )
+ throws StandardException {
ExecRow nextRow = super.getNextRowCore( source );
if ( (nextRow != null) && constants.underMerge() ) {
@@ -1086,16 +1075,15 @@ class InsertResultSet extends DMLWriteGe
}
return nextRow;
- }
+ }
/**
* <p>
* Special handling if this is an INSERT action of a MERGE statement.
* </p>
*/
- private ExecRow processMergeRow( NoPutResultSet sourceRS, ExecRow row )
- throws StandardException
- {
+ private ExecRow processMergeRow( NoPutResultSet sourceRS, ExecRow row )
+ throws StandardException {
//
// The normal processing of autogenerated columns happens in
// the evaluation of the driving ResultSet. That processing assumes
@@ -1116,9 +1104,12 @@ class InsertResultSet extends DMLWriteGe
// If the identity column was declared BY DEFAULT, then it could be
// overridden by the WHEN NOT MATCHED clause. In that case, the
// row will contain a non-null value which we do not want to clobber.
+ // Commented code preserves previous attempts to solve this situation--
+ // in case this issue needs to be revisited.
//
//boolean needToGenerateValue = ( dvd == null ) || ( dvd.isNullOp().getBoolean() );
- boolean needToGenerateValue = ( dvd == null );
+ //boolean needToGenerateValue = ( dvd == null );
+ boolean needToGenerateValue = ( dvd == null ) || constants.autoincrementColumnSetToDEFAULT();
if ( needToGenerateValue )
{
@@ -1129,79 +1120,78 @@ class InsertResultSet extends DMLWriteGe
}
return normalizeRow( sourceRS, row );
- }
+ }
- // Do the work for a bulk insert
+ // Do the work for a bulk insert
private void bulkInsertCore(LanguageConnectionContext lcc,
ExecRow fullTemplate,
- long oldHeapConglom)
- throws StandardException
- {
- bulkHeapCC = tc.openCompiledConglomerate(
- false,
- TransactionController.OPENMODE_FORUPDATE,
- TransactionController.MODE_TABLE,
- TransactionController.ISOLATION_SERIALIZABLE,
- constants.heapSCOCI,
- heapDCOCI);
+ long oldHeapConglom)
+ throws StandardException {
+ bulkHeapCC = tc.openCompiledConglomerate(
+ false,
+ TransactionController.OPENMODE_FORUPDATE,
+ TransactionController.MODE_TABLE,
+ TransactionController.ISOLATION_SERIALIZABLE,
+ constants.heapSCOCI,
+ heapDCOCI);
- long newHeapConglom;
+ long newHeapConglom;
- Properties properties = new Properties();
+ Properties properties = new Properties();
- // Get the properties on the old heap
- bulkHeapCC.getInternalTablePropertySet(properties);
+ // Get the properties on the old heap
+ bulkHeapCC.getInternalTablePropertySet(properties);
if (triggerInfo != null) {
// no triggers in bulk insert mode
if (SanityManager.DEBUG) {
SanityManager.NOTREACHED();
}
- }
+ }
+
+ /*
+ ** If we have a before row trigger, then we
+ ** are going to use a row holder pass to our
+ ** trigger.
+ */
+ if (hasBeforeRowTrigger && rowHolder != null)
+ {
+ rowHolder =
+ new TemporaryRowHolderImpl(activation, properties,
+ resultDescription);
+ }
- /*
- ** If we have a before row trigger, then we
- ** are going to use a row holder pass to our
- ** trigger.
- */
- if (hasBeforeRowTrigger && rowHolder != null)
- {
- rowHolder =
- new TemporaryRowHolderImpl(activation, properties,
- resultDescription);
- }
-
- // Add any new properties or change the values of any existing properties
- Properties targetProperties = constants.getTargetProperties();
- Enumeration key = targetProperties.keys();
- while (key.hasMoreElements())
- {
- String keyValue = (String) key.nextElement();
- properties.put(keyValue, targetProperties.getProperty(keyValue));
- }
-
- // Are there indexes to be updated?
- if (constants.irgs.length > 0)
- {
- // Tell source whether or not we need the RIDs back
- sourceResultSet.setNeedsRowLocation(true);
- }
+ // Add any new properties or change the values of any existing properties
+ Properties targetProperties = constants.getTargetProperties();
+ Enumeration key = targetProperties.keys();
+ while (key.hasMoreElements())
+ {
+ String keyValue = (String) key.nextElement();
+ properties.put(keyValue, targetProperties.getProperty(keyValue));
+ }
+
+ // Are there indexes to be updated?
+ if (constants.irgs.length > 0)
+ {
+ // Tell source whether or not we need the RIDs back
+ sourceResultSet.setNeedsRowLocation(true);
+ }
if (constants.hasDeferrableChecks) {
sourceResultSet.setHasDeferrableChecks();
}
- dd = lcc.getDataDictionary();
- td = dd.getTableDescriptor(constants.targetUUID);
+ dd = lcc.getDataDictionary();
+ td = dd.getTableDescriptor(constants.targetUUID);
- /* Do the bulk insert - only okay to reuse the
- * same conglomerate if bulkInsert.
- */
- long[] loadedRowCount = new long[1];
- if (bulkInsertReplace)
- {
- newHeapConglom =
+ /* Do the bulk insert - only okay to reuse the
+ * same conglomerate if bulkInsert.
+ */
+ long[] loadedRowCount = new long[1];
+ if (bulkInsertReplace)
+ {
+ newHeapConglom =
tc.createAndLoadConglomerate(
"heap",
fullTemplate.getRowArray(),
@@ -1211,10 +1201,10 @@ class InsertResultSet extends DMLWriteGe
TransactionController.IS_DEFAULT,
sourceResultSet,
loadedRowCount);
- }
- else
- {
- newHeapConglom =
+ }
+ else
+ {
+ newHeapConglom =
tc.recreateAndLoadConglomerate(
"heap",
false,
@@ -1226,32 +1216,32 @@ class InsertResultSet extends DMLWriteGe
oldHeapConglom,
sourceResultSet,
loadedRowCount);
- }
+ }
- /* Nothing else to do if we get back the same conglomerate number.
- * (In 2.0 this means that 0 rows were inserted.)
- */
- if (newHeapConglom == oldHeapConglom)
- {
+ /* Nothing else to do if we get back the same conglomerate number.
+ * (In 2.0 this means that 0 rows were inserted.)
+ */
+ if (newHeapConglom == oldHeapConglom)
+ {
return;
- }
+ }
- // Find out how many rows were inserted
- rowCount = loadedRowCount[0];
+ // Find out how many rows were inserted
+ rowCount = loadedRowCount[0];
- // Set the "estimated" row count
- setEstimatedRowCount(newHeapConglom);
+ // Set the "estimated" row count
+ setEstimatedRowCount(newHeapConglom);
- /*
- ** Inform the data dictionary that we are about to write to it.
- ** There are several calls to data dictionary "get" methods here
- ** that might be done in "read" mode in the data dictionary, but
- ** it seemed safer to do this whole operation in "write" mode.
- **
- ** We tell the data dictionary we're done writing at the end of
- ** the transaction.
- */
- dd.startWriting(lcc);
+ /*
+ ** Inform the data dictionary that we are about to write to it.
+ ** There are several calls to data dictionary "get" methods here
+ ** that might be done in "read" mode in the data dictionary, but
+ ** it seemed safer to do this whole operation in "write" mode.
+ **
+ ** We tell the data dictionary we're done writing at the end of
+ ** the transaction.
+ */
+ dd.startWriting(lcc);
//
// If we were doing bulkInsert, then we need to flush the last
@@ -1272,388 +1262,384 @@ class InsertResultSet extends DMLWriteGe
}
}
- // invalidate any prepared statements that
- // depended on this table (including this one)
- DependencyManager dm = dd.getDependencyManager();
+ // invalidate any prepared statements that
+ // depended on this table (including this one)
+ DependencyManager dm = dd.getDependencyManager();
- dm.invalidateFor(td, DependencyManager.BULK_INSERT, lcc);
+ dm.invalidateFor(td, DependencyManager.BULK_INSERT, lcc);
- // Update all indexes
- if (constants.irgs.length > 0)
- {
+ // Update all indexes
+ if (constants.irgs.length > 0)
+ {
// MEN VI HAR MANGE SORTS, EN PR INDEX: alle blir droppet, hvordan
// assossiere alle med nye indekser som tildeles inni her???
// FIXME!!
- updateAllIndexes(newHeapConglom, constants, td, dd, fullTemplate);
- }
+ updateAllIndexes(newHeapConglom, constants, td, dd, fullTemplate);
+ }
- // Drop the old conglomerate
- bulkHeapCC.close();
- bulkHeapCC = null;
-
- /* Update the DataDictionary
- * RESOLVE - this will change in 1.4 because we will get
- * back the same conglomerate number
- */
- // Get the ConglomerateDescriptor for the heap
- ConglomerateDescriptor cd = td.getConglomerateDescriptor(oldHeapConglom);
-
- // Update sys.sysconglomerates with new conglomerate #
- dd.updateConglomerateDescriptor(cd, newHeapConglom, tc);
- tc.dropConglomerate(oldHeapConglom);
- // END RESOLVE
- }
+ // Drop the old conglomerate
+ bulkHeapCC.close();
+ bulkHeapCC = null;
+
+ /* Update the DataDictionary
+ * RESOLVE - this will change in 1.4 because we will get
+ * back the same conglomerate number
+ */
+ // Get the ConglomerateDescriptor for the heap
+ ConglomerateDescriptor cd = td.getConglomerateDescriptor(oldHeapConglom);
+
+ // Update sys.sysconglomerates with new conglomerate #
+ dd.updateConglomerateDescriptor(cd, newHeapConglom, tc);
+ tc.dropConglomerate(oldHeapConglom);
+ // END RESOLVE
+ }
- /**
- ** Bulk Referential Integrity Checker
- */
+ /**
+ ** Bulk Referential Integrity Checker
+ */
private void bulkValidateForeignKeys(
- TransactionController tc, ContextManager cm, ExecRow fullTemplate)
- throws StandardException
- {
- /*
- ** If there are no foreign keys, then nothing to worry
- ** about.
- ** With bulk insert replace, we still need to verify
- ** all non-self referencing foreign keys when
- ** there are no rows inserted into the table.
- */
- if ((indexRows == null && !bulkInsertReplace) ||
- fkInfoArray == null)
- {
- return;
- }
+ TransactionController tc, ContextManager cm, ExecRow fullTemplate)
+ throws StandardException {
+ /*
+ ** If there are no foreign keys, then nothing to worry
+ ** about.
+ ** With bulk insert replace, we still need to verify
+ ** all non-self referencing foreign keys when
+ ** there are no rows inserted into the table.
+ */
+ if ((indexRows == null && !bulkInsertReplace) ||
+ fkInfoArray == null)
+ {
+ return;
+ }
for (FKInfo fkInfo : fkInfoArray)
- {
+ {
- /* With regular bulk insert, we only need to check the
- * foreign keys in the table we inserted into. We need
- * to get the new conglomerate #s for the foreign keys.
- *
- * With bulk insert replace, we need to check both the
- * foreign keys in the table as well as any foreign keys
- * on other tables referencing the table we inserted into.
- * If the foreign key is self-referencing then we need to
- * get the new conglomerate #, otherwise the conglomerate
- * # is the same as the compile time conglomerate #.
- * If the foreign key is self-referencing then we need to
- * get the new conglomerate # for the primary key as it
- * has changed. However, if the foreign key is not self-referencing
- * then we only need to get the new conglomerate # for
- * the primary key if the primary key is on the table being
- * inserted into.
- */
- if (bulkInsertReplace)
- {
- for (int index = 0; index < fkInfo.fkConglomNumbers.length; index++)
- {
- /* No need to check foreign key if it is self referencing
- * and there were no rows inserted on the replace, as both
- * indexes will be empty.
- */
- if (fkInfo.fkIsSelfReferencing[index] && indexRows == null)
- {
- continue;
- }
-
- long pkConglom;
- long fkConglom;
-
- if (fkInfo.fkIsSelfReferencing[index])
- {
- /* Self-referencing foreign key. Both conglomerate
- * #s have changed.
- */
- pkConglom = (indexConversionTable.get(
- Long.valueOf(fkInfo.refConglomNumber))).longValue();
- fkConglom = (indexConversionTable.get(
- Long.valueOf(fkInfo.fkConglomNumbers[index]))).
+ /* With regular bulk insert, we only need to check the
+ * foreign keys in the table we inserted into. We need
+ * to get the new conglomerate #s for the foreign keys.
+ *
+ * With bulk insert replace, we need to check both the
+ * foreign keys in the table as well as any foreign keys
+ * on other tables referencing the table we inserted into.
+ * If the foreign key is self-referencing then we need to
+ * get the new conglomerate #, otherwise the conglomerate
+ * # is the same as the compile time conglomerate #.
+ * If the foreign key is self-referencing then we need to
+ * get the new conglomerate # for the primary key as it
+ * has changed. However, if the foreign key is not self-referencing
+ * then we only need to get the new conglomerate # for
+ * the primary key if the primary key is on the table being
+ * inserted into.
+ */
+ if (bulkInsertReplace)
+ {
+ for (int index = 0; index < fkInfo.fkConglomNumbers.length; index++)
+ {
+ /* No need to check foreign key if it is self referencing
+ * and there were no rows inserted on the replace, as both
+ * indexes will be empty.
+ */
+ if (fkInfo.fkIsSelfReferencing[index] && indexRows == null)
+ {
+ continue;
+ }
+
+ long pkConglom;
+ long fkConglom;
+
+ if (fkInfo.fkIsSelfReferencing[index])
+ {
+ /* Self-referencing foreign key. Both conglomerate
+ * #s have changed.
+ */
+ pkConglom = (indexConversionTable.get(
+ Long.valueOf(fkInfo.refConglomNumber))).longValue();
+ fkConglom = (indexConversionTable.get(
+ Long.valueOf(fkInfo.fkConglomNumbers[index]))).
longValue();
- }
- else
- {
- /* Non-self referencing foreign key. At this point we
- * don't know if the primary key or the foreign key is
- * on this table. So, for each one, we look to see
- * if the old conglomerate # is in the conversion table.
- * If so, then we get the new conglomerate #, otherwise
- * we use the compile time conglomerate #. This
- * is very simple, though not very elegant.
- */
- Long pkConglomLong = indexConversionTable.get(
+ }
+ else
+ {
+ /* Non-self referencing foreign key. At this point we
+ * don't know if the primary key or the foreign key is
+ * on this table. So, for each one, we look to see
+ * if the old conglomerate # is in the conversion table.
+ * If so, then we get the new conglomerate #, otherwise
+ * we use the compile time conglomerate #. This
+ * is very simple, though not very elegant.
+ */
+ Long pkConglomLong = indexConversionTable.get(
Long.valueOf(fkInfo.refConglomNumber));
- Long fkConglomLong = indexConversionTable.get(
+ Long fkConglomLong = indexConversionTable.get(
Long.valueOf(fkInfo.fkConglomNumbers[index]));
- if (pkConglomLong == null)
- {
- pkConglom = fkInfo.refConglomNumber;
- }
- else
- {
- pkConglom = pkConglomLong.longValue();
- }
- if (fkConglomLong == null)
- {
- fkConglom = fkInfo.fkConglomNumbers[index];
- }
- else
- {
- fkConglom = fkConglomLong.longValue();
- }
- }
- bulkValidateForeignKeysCore(
- tc, cm, fkInfo, fkConglom, pkConglom,
- fkInfo.fkConstraintNames[index], fullTemplate);
- }
- }
- else
- {
- /*
- ** We have a FKInfo for each foreign key we are
- ** checking. Note that there are no primary key
- ** checks on insert, so we can always reference
- ** element[0] in the current FKInfo structure.
- */
- if (SanityManager.DEBUG)
- {
- SanityManager.ASSERT(fkInfo.type == FKInfo.FOREIGN_KEY,
- "error, expected to only check foreign keys on insert");
- }
- Long fkConglom = indexConversionTable.get(fkInfo.fkConglomNumbers[0]);
- bulkValidateForeignKeysCore(
- tc, cm, fkInfo, fkConglom.longValue(),
- fkInfo.refConglomNumber, fkInfo.fkConstraintNames[0],
- fullTemplate);
- }
- }
- }
+ if (pkConglomLong == null)
+ {
+ pkConglom = fkInfo.refConglomNumber;
+ }
+ else
+ {
+ pkConglom = pkConglomLong.longValue();
+ }
+ if (fkConglomLong == null)
+ {
+ fkConglom = fkInfo.fkConglomNumbers[index];
+ }
+ else
+ {
+ fkConglom = fkConglomLong.longValue();
+ }
+ }
+ bulkValidateForeignKeysCore(
+ tc, cm, fkInfo, fkConglom, pkConglom,
+ fkInfo.fkConstraintNames[index], fullTemplate);
+ }
+ }
+ else
+ {
+ /*
+ ** We have a FKInfo for each foreign key we are
+ ** checking. Note that there are no primary key
+ ** checks on insert, so we can always reference
+ ** element[0] in the current FKInfo structure.
+ */
+ if (SanityManager.DEBUG)
+ {
+ SanityManager.ASSERT(fkInfo.type == FKInfo.FOREIGN_KEY,
+ "error, expected to only check foreign keys on insert");
+ }
+ Long fkConglom = indexConversionTable.get(fkInfo.fkConglomNumbers[0]);
+ bulkValidateForeignKeysCore(
+ tc, cm, fkInfo, fkConglom.longValue(),
+ fkInfo.refConglomNumber, fkInfo.fkConstraintNames[0],
+ fullTemplate);
+ }
+ }
+ }
- private void bulkValidateForeignKeysCore(
- TransactionController tc, ContextManager cm,
- FKInfo fkInfo, long fkConglom, long pkConglom,
- String fkConstraintName, ExecRow fullTemplate)
- throws StandardException
- {
- ExecRow template;
- GroupFetchScanController refScan = null;
- GroupFetchScanController fkScan = null;
-
- try
- {
-
- template = makeIndexTemplate(fkInfo, fullTemplate, cm);
-
- /*
- ** The indexes have been dropped and recreated, so
- ** we need to get the new index conglomerate number.
- */
- fkScan =
- tc.openGroupFetchScan(
- fkConglom,
- false, // hold
- 0, // read only
- // doesn't matter, already locked
- TransactionController.MODE_TABLE,
- // doesn't matter, already locked
- TransactionController.ISOLATION_READ_COMMITTED,
- (FormatableBitSet)null, // retrieve all fields
- (DataValueDescriptor[])null, // startKeyValue
- ScanController.GE, // startSearchOp
- null, // qualifier
- (DataValueDescriptor[])null, // stopKeyValue
- ScanController.GT // stopSearchOp
- );
+ private void bulkValidateForeignKeysCore(
+ TransactionController tc, ContextManager cm,
+ FKInfo fkInfo, long fkConglom, long pkConglom,
+ String fkConstraintName, ExecRow fullTemplate)
+ throws StandardException {
+ ExecRow template;
+ GroupFetchScanController refScan = null;
+ GroupFetchScanController fkScan = null;
- if (SanityManager.DEBUG)
- {
- /*
- ** Bulk insert replace calls this method regardless
- ** of whether or not any rows were inserted because
- ** it has to check any referencing foreign keys
- ** after the replace. Otherwise, we
- ** make sure that we actually have a row in the fk.
- ** If not, we have an error because we thought that
- ** since indexRows != null, we must have gotten some
- ** rows.
- */
- if (! bulkInsertReplace)
- {
- SanityManager.ASSERT(fkScan.next(),
- "No rows in fk index, even though indexRows != null");
+ try
+ {
+
+ template = makeIndexTemplate(fkInfo, fullTemplate, cm);
+
+ /*
+ ** The indexes have been dropped and recreated, so
+ ** we need to get the new index conglomerate number.
+ */
+ fkScan =
+ tc.openGroupFetchScan(
+ fkConglom,
+ false, // hold
+ 0, // read only
+ // doesn't matter, already locked
+ TransactionController.MODE_TABLE,
+ // doesn't matter, already locked
+ TransactionController.ISOLATION_READ_COMMITTED,
+ (FormatableBitSet)null, // retrieve all fields
+ (DataValueDescriptor[])null, // startKeyValue
+ ScanController.GE, // startSearchOp
+ null, // qualifier
+ (DataValueDescriptor[])null, // stopKeyValue
+ ScanController.GT // stopSearchOp
+ );
+
+ if (SanityManager.DEBUG)
+ {
+ /*
+ ** Bulk insert replace calls this method regardless
+ ** of whether or not any rows were inserted because
+ ** it has to check any referencing foreign keys
+ ** after the replace. Otherwise, we
+ ** make sure that we actually have a row in the fk.
+ ** If not, we have an error because we thought that
+ ** since indexRows != null, we must have gotten some
+ ** rows.
+ */
+ if (! bulkInsertReplace)
+ {
+ SanityManager.ASSERT(fkScan.next(),
+ "No rows in fk index, even though indexRows != null");
- /*
- ** Crank up the scan again.
- */
- fkScan.reopenScan(
- (DataValueDescriptor[])null, // startKeyValue
- ScanController.GE, // startSearchOp
- null, // qualifier
- (DataValueDescriptor[])null, // stopKeyValue
- ScanController.GT // stopSearchOp
- );
- }
- }
-
- /*
- ** Open the referenced key scan. Use row locking on
- ** the referenced table unless it is self-referencing
- ** (in which case we don't need locks)
- */
- refScan =
- tc.openGroupFetchScan(
- pkConglom,
- false, // hold
- 0, // read only
- (fkConglom == pkConglom) ?
- TransactionController.MODE_TABLE :
- TransactionController.MODE_RECORD,
- // read committed is good enough
- TransactionController.ISOLATION_READ_COMMITTED,
- (FormatableBitSet)null, // retrieve all fields
- (DataValueDescriptor[])null, // startKeyValue
- ScanController.GE, // startSearchOp
- null, // qualifier
- (DataValueDescriptor[])null, // stopKeyValue
- ScanController.GT // stopSearchOp
- );
-
- /*
- ** Give the scans to the bulk checker to do its
- ** magic. It will do a merge on the two indexes.
- */
- ExecRow firstFailedRow = template.getClone();
- RIBulkChecker riChecker = new RIBulkChecker(activation,
- refScan,
- fkScan,
- template,
- true, // fail on 1st failure
- (ConglomerateController)null,
- firstFailedRow,
- fkInfo.schemaName,
- fkInfo.tableName,
- fkInfo.fkIds[0],
- fkInfo.deferrable[0],
- fkConglom,
- pkConglom);
+ /*
+ ** Crank up the scan again.
+ */
+ fkScan.reopenScan(
+ (DataValueDescriptor[])null, // startKeyValue
+ ScanController.GE, // startSearchOp
+ null, // qualifier
+ (DataValueDescriptor[])null, // stopKeyValue
+ ScanController.GT // stopSearchOp
+ );
+ }
+ }
+
+ /*
+ ** Open the referenced key scan. Use row locking on
+ ** the referenced table unless it is self-referencing
+ ** (in which case we don't need locks)
+ */
+ refScan =
+ tc.openGroupFetchScan(
+ pkConglom,
+ false, // hold
+ 0, // read only
+ (fkConglom == pkConglom) ?
+ TransactionController.MODE_TABLE :
+ TransactionController.MODE_RECORD,
+ // read committed is good enough
+ TransactionController.ISOLATION_READ_COMMITTED,
+ (FormatableBitSet)null, // retrieve all fields
+ (DataValueDescriptor[])null, // startKeyValue
+ ScanController.GE, // startSearchOp
+ null, // qualifier
+ (DataValueDescriptor[])null, // stopKeyValue
+ ScanController.GT // stopSearchOp
+ );
+
+ /*
+ ** Give the scans to the bulk checker to do its
+ ** magic. It will do a merge on the two indexes.
+ */
+ ExecRow firstFailedRow = template.getClone();
+ RIBulkChecker riChecker = new RIBulkChecker(activation,
+ refScan,
+ fkScan,
+ template,
+ true, // fail on 1st failure
+ (ConglomerateController)null,
+ firstFailedRow,
+ fkInfo.schemaName,
+ fkInfo.tableName,
+ fkInfo.fkIds[0],
+ fkInfo.deferrable[0],
+ fkConglom,
+ pkConglom);
- int numFailures = riChecker.doCheck();
- if (numFailures > 0)
- {
- StandardException se = StandardException.newException(SQLState.LANG_FK_VIOLATION, fkConstraintName,
- fkInfo.tableName,
- StatementUtil.typeName(fkInfo.stmtType),
- RowUtil.toString(firstFailedRow, 0, fkInfo.colArray.length - 1));
- throw se;
- }
- }
- finally
- {
- if (fkScan != null)
[... 1535 lines stripped ...]