📄 insertresultset.java
字号:
} rowCount = 0; 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); long baseTableConglom = bulkInsertCore(lcc, heapConglom); if (hasBeforeStatementTrigger) { tableScan = getTableScanResultSet(baseTableConglom); // fire BEFORE trigger, do this before checking constraints triggerActivator.notifyEvent(TriggerEvents.BEFORE_INSERT, (CursorResultSet)null, tableScan); // if we have a check constraint, we have // to do it the hard way now before we get // to our AFTER triggers. if (checkGM != null) { tableScan = getTableScanResultSet(baseTableConglom); try { ExecRow currRow = null; while ((currRow = tableScan.getNextRowCore()) != null) { // we have to set the source row so the check constraint // sees the correct row. sourceResultSet.setCurrentRow(currRow); evaluateCheckConstraints(); } } finally { sourceResultSet.clearCurrentRow(); } } } bulkValidateForeignKeys(tc, lcc.getContextManager()); // if we have an AFTER trigger, let 'er rip if ((triggerInfo != null) && (triggerInfo.hasTrigger(false, true) || triggerInfo.hasTrigger(false, false))) { triggerActivator.notifyEvent(TriggerEvents.AFTER_INSERT, (CursorResultSet)null, getTableScanResultSet(baseTableConglom)); } 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; } /* autoGeneratedResultset for JDBC3. Nulled after statement execution is over (ie after it is saved off in LocalSatement object) */ if (activation.getAutoGeneratedKeysResultsetMode()) autoGeneratedKeysResultSet = autoGeneratedKeysRowsHolder.getResultSet(); else autoGeneratedKeysResultSet = null; cleanUp(); if (aiCache != null) { Hashtable aiHashtable = new Hashtable(); int numColumns = aiCache.length; // this insert updated ai values, store them in some persistent // place so that I can see these values. for (int i = 0; i < numColumns; i++) { if (aiCache[i] == null) continue; aiHashtable.put(AutoincrementCounter.makeIdentity( constants.getSchemaName(), constants.getTableName(), constants.getColumnName(i)), new Long(aiCache[i].getLong())); } InternalTriggerExecutionContext itec = (InternalTriggerExecutionContext)lcc.getTriggerExecutionContext(); if (itec == null) lcc.copyHashtableToAIHT(aiHashtable); else itec.copyHashtableToAIHT(aiHashtable); } endTime = getCurrentTimeMillis(); } /* * Verify that the auto-generated columns list (by position) has valid * column positions for the table. */ private void verifyAutoGeneratedColumnsIndexes(int[] columnIndexes) throws StandardException { int size = columnIndexes.length; TableDescriptor td = dd.getTableDescriptor(constants.targetUUID); // all 1-based column ids. for (int i = 0; i < size; i++) { if (td.getColumnDescriptor(columnIndexes[i]) == null) throw StandardException.newException(SQLState.LANG_COLUMN_POSITION_NOT_FOUND, new Integer(columnIndexes[i])); } } /* * 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 td = dd.getTableDescriptor(constants.targetUUID); ColumnDescriptor cd; int size = td.getMaxColumnID(); int[] generatedColumnPositionsArray = new int[size]; int generatedColumnNumbers = 0; for (int i=0; i<size; i++) { generatedColumnPositionsArray[i] = -1; } for (int i=0; i<size; i++) { cd = td.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]; } return returnGeneratedColumnPositionsArray; } /* * Remove duplicate columns from the array. Then use this array to generate a sub-set * of insert resultset to be returned for JDBC3.0 getGeneratedKeys() call. */ private int[] uniqueColumnPositionArray(int[] columnIndexes) throws StandardException { int size = columnIndexes.length; TableDescriptor td = dd.getTableDescriptor(constants.targetUUID); //create an array of integer (the array size = number of columns in table) // valid column positions are 1...getMaxColumnID() int[] uniqueColumnIndexes = new int[td.getMaxColumnID()]; int uniqueColumnNumbers = 0; //At the end of following loop, the uniqueColumnIndexes elements will not be 0 for user //selected auto-generated columns. for (int i=0; i<size; i++) { if (uniqueColumnIndexes[columnIndexes[i] - 1] == 0) { uniqueColumnNumbers++; uniqueColumnIndexes[columnIndexes[i] - 1] = columnIndexes[i]; } } int[] returnUniqueColumnIndexes = new int[uniqueColumnNumbers]; //return just the column positions which are not marked 0 in the uniqueColumnIndexes array for (int i=0, j=0; i<uniqueColumnIndexes.length; i++) { if (uniqueColumnIndexes[i] != 0) returnUniqueColumnIndexes[j++] = uniqueColumnIndexes[i]; } return returnUniqueColumnIndexes; } /** * Verify that the auto-generated columns list (by name) has valid * column names for the table. If all the column names are valid, * convert column names array to corresponding column positions array * Save that column positions array in activation. We do this to simplify the * rest of the logic(it only has to deal with column positions here after). * * @return Nothing. * * @exception StandardException Thrown on error if invalid column * name in the list. */ private void verifyAutoGeneratedColumnsNames(String[] columnNames) throws StandardException { int size = columnNames.length; int columnPositions[] = new int[size]; TableDescriptor td = dd.getTableDescriptor(constants.targetUUID); ColumnDescriptor cd; for (int i = 0; i < size; i++) { if (columnNames[i] == null) throw StandardException.newException(SQLState.LANG_COLUMN_NAME_NOT_FOUND, columnNames[i]); cd = td.getColumnDescriptor(columnNames[i]); if (cd == null) throw StandardException.newException(SQLState.LANG_COLUMN_NAME_NOT_FOUND, columnNames[i]); else columnPositions[i] = cd.getPosition(); } activation.setAutoGeneratedKeysResultsetInfo(columnPositions, null); } /** * @see ResultSet#getAutoGeneratedKeysResultset */ public ResultSet getAutoGeneratedKeysResultset() { return autoGeneratedKeysResultSet; } /** * 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 { 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 Cloudscape * 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 { nestedTC = tc.startNestedUserTransaction(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) { nestedTC.commit(); nestedTC.destroy(); } } aiCache[index] = newValue; if (setIdentity) identityVal = newValue.getLong(); } return aiCache[index]; } // Is sourceResultSet a RowResultSet (values clause)? private boolean isSourceRowResultSet () { boolean isRow = false; 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 firstDeferredRow = true; ExecRow deferredRowBuffer = null; /* Get or re-use the row changer. * NOTE: We need to set ourself as the top result set * if this is not the 1st execution. (Done in constructor * for 1st execution.) */ if (firstExecute) { rowChanger = lcc.getLanguageConnectionFactory().getExecutionFactory() .getRowChanger( heapConglom, constants.heapSCOCI, heapDCOCI, constants.irgs, constants.indexCIDS, constants.indexSCOCIs, indexDCOCIs,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -