use of org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo in project derby by apache.
the class InsertResultSet method normalInsertCore.
// 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, // number of columns in partial row meaningless for insert
0, tc, // Changed column ids
null, 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);
}
firstExecuteSpecialHandlingAutoGen(firstExecute, rowChanger, constants.targetUUID);
while (row != null) {
// auto-generated key columns.
if (activation.getAutoGeneratedKeysResultsetMode() && autoGeneratedKeysColumnIndexes.length > 0) {
autoGeneratedKeysRowsHolder.insert(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 {
// 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) {
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;
}
if (rowArray[i] instanceof StreamStorable)
rowArray[i].getObject();
}
}
if (allOk) {
rowChanger.insertRow(row, false);
} else {
RowLocation offendingRow = rowChanger.insertRow(row, true);
deferredChecks = DeferredConstraintsMemory.rememberCheckViolations(lcc, constants.targetUUID, schemaName, tableName, deferredChecks, violatingCheckConstraints, offendingRow, new CheckInfo[1]);
}
}
rowCount++;
if (setUserIdentity) {
dd = lcc.getDataDictionary();
td = dd.getTableDescriptor(constants.targetUUID);
int maxColumns = td.getMaxColumnID();
int col;
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();
}
}
// 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;
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) {
rowChanger.insertRow(deferredRowBuffer, false);
} else {
RowLocation offendingRow = rowChanger.insertRow(deferredRowBuffer, true);
deferredChecks = DeferredConstraintsMemory.rememberCheckViolations(lcc, constants.targetUUID, schemaName, tableName, deferredChecks, violatingCheckConstraints, offendingRow, new CheckInfo[1]);
}
}
} 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);
else /*
* find the value of the identity column from the user inserted value
* and do a lcc.setIdentityValue(<user_value>);
*/
if (setUserIdentity) {
lcc.setIdentityValue(user_autoinc);
}
}
use of org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo in project derby by apache.
the class UpdateResultSet method collectAffectedRows.
public boolean collectAffectedRows() throws StandardException {
boolean rowsFound = false;
row = getNextRowCore(sourceResultSet);
if (row != null)
rowsFound = true;
else {
activation.addWarning(StandardException.newWarning(SQLState.LANG_NO_ROW_FOUND));
}
// beetle 3865, update cursor use index.
TableScanResultSet tableScan = (TableScanResultSet) activation.getForUpdateIndexScan();
boolean notifyCursor = (tableScan != null);
boolean checkStream = (deferred && rowsFound && !constants.singleRowSource);
FormatableBitSet streamCols = (checkStream ? checkStreamCols() : null);
checkStream = (streamCols != null);
while (row != null) {
evaluateGenerationClauses(generationClauses, activation, sourceResultSet, row, true);
/*
** If we're doing deferred update, write the new row and row
** location to the temporary conglomerate. If we're not doing
** deferred update, update the permanent conglomerates now
** using the RowChanger.
*/
if (deferred) {
/*
** If we have a before trigger, we must evaluate the
** check constraint after we have executed the trigger.
** Note that we have compiled checkGM accordingly (to
** handle the different row shape if we are evaluating
** against the input result set or a temporary row holder
** result set).
*/
if (triggerInfo == null) {
boolean allOk = evaluateCheckConstraints();
if (!allOk) {
DataValueDescriptor[] rw = row.getRowArray();
SQLRef r = (SQLRef) rw[rw.length - 1];
RowLocation baseRowLocation = (RowLocation) r.getObject();
deferredChecks = DeferredConstraintsMemory.rememberCheckViolations(lcc, constants.targetUUID, constants.getSchemaName(), constants.getTableName(), deferredChecks, violatingCheckConstraints, baseRowLocation, new CheckInfo[1]);
}
}
/*
** We are going to only save off the updated
** columns and the RID. For a trigger, all columns
** were marked as needed so we'll copy them all.
*/
RowUtil.copyRefColumns(deferredTempRow, row, numberOfBaseColumns, numberOfBaseColumns + 1);
if (checkStream)
objectifyStream(deferredTempRow, streamCols);
insertedRowHolder.insert(deferredTempRow);
/*
** Grab a copy of the row to delete. We are
** going to use this for deferred RI checks.
*/
if (beforeUpdateCopyRequired) {
RowUtil.copyRefColumns(oldDeletedRow, row, numberOfBaseColumns);
deletedRowHolder.insert(oldDeletedRow);
}
/*
** If we haven't already, lets get a template to
** use as a template for our rescan of the base table.
** Do this now while we have a real row to use
** as a copy.
**
** There is one less column in the base row than
** there is in source row, because the base row
** doesn't contain the row location.
*/
if (deferredBaseRow == null) {
deferredBaseRow = RowUtil.getEmptyValueRow(numberOfBaseColumns, lcc);
RowUtil.copyCloneColumns(deferredBaseRow, row, numberOfBaseColumns);
/*
** While we're here, let's also create a sparse row for
** fetching from the store.
*/
deferredSparseRow = makeDeferredSparseRow(deferredBaseRow, baseRowReadList, lcc);
}
} else {
boolean allOk = evaluateCheckConstraints();
/* Get the RowLocation to update
* NOTE - Column #s in the Row are 1 based.
*/
RowLocation baseRowLocation = (RowLocation) (row.getColumn(resultWidth)).getObject();
if (!allOk) {
deferredChecks = DeferredConstraintsMemory.rememberCheckViolations(lcc, constants.targetUUID, constants.getSchemaName(), constants.getTableName(), deferredChecks, violatingCheckConstraints, baseRowLocation, new CheckInfo[1]);
}
RowUtil.copyRefColumns(newBaseRow, row, numberOfBaseColumns, numberOfBaseColumns);
if (riChecker != null) {
/*
** Make sure all foreign keys in the new row
** are maintained. Note that we don't bother
** checking primary/unique keys that are referenced
** here. The reason is that if we are updating
** a referenced key, we'll be updating in deferred
** mode, so we wont get here.
*/
riChecker.doFKCheck(activation, newBaseRow);
}
sourceResultSet.updateRow(newBaseRow, rowChanger);
rowChanger.updateRow(row, newBaseRow, baseRowLocation);
// beetle 3865, update cursor use index.
if (notifyCursor)
notifyForUpdateCursor(row.getRowArray(), newBaseRow.getRowArray(), baseRowLocation, tableScan);
}
rowCount++;
// No need to do a next on a single row source
if (constants.singleRowSource) {
row = null;
} else {
row = getNextRowCore(sourceResultSet);
}
}
if (rowCount == 1 && constants.hasAutoincrement())
lcc.setIdentityValue(identityVal);
return rowsFound;
}
use of org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo in project derby by apache.
the class UpdateResultSet method updateDeferredRows.
void updateDeferredRows() throws StandardException {
if (deferred) {
// we already have everything locked
deferredBaseCC = tc.openCompiledConglomerate(false, (TransactionController.OPENMODE_SECONDARY_LOCKED | TransactionController.OPENMODE_FORUPDATE), lockMode, TransactionController.ISOLATION_SERIALIZABLE, constants.heapSCOCI, heapDCOCI);
CursorResultSet rs = insertedRowHolder.getResultSet();
try {
/*
** We need to do a fetch doing a partial row
** read. We need to shift our 1-based bit
** set to a zero based bit set like the store
** expects.
*/
FormatableBitSet readBitSet = RowUtil.shift(baseRowReadList, 1);
ExecRow deferredTempRow2;
rs.open();
while ((deferredTempRow2 = rs.getNextRow()) != null) {
/*
** Check the constraint now if we have triggers.
** Otherwise we evaluated them as we read the
** rows in from the source.
*/
boolean allOk = true;
if (triggerInfo != null) {
sourceResultSet.setCurrentRow(deferredTempRow);
allOk = evaluateCheckConstraints();
}
/*
** The last column is a Ref, which contains a
** RowLocation.
*/
DataValueDescriptor rlColumn = deferredTempRow2.getColumn(numberOfBaseColumns + 1);
RowLocation baseRowLocation = (RowLocation) (rlColumn).getObject();
if (!allOk) {
deferredChecks = DeferredConstraintsMemory.rememberCheckViolations(lcc, constants.targetUUID, constants.getSchemaName(), constants.getTableName(), deferredChecks, violatingCheckConstraints, baseRowLocation, new CheckInfo[1]);
}
/* Get the base row at the given RowLocation */
boolean row_exists = deferredBaseCC.fetch(baseRowLocation, deferredSparseRow.getRowArray(), readBitSet);
if (SanityManager.DEBUG) {
SanityManager.ASSERT(row_exists, "did not find base row in deferred update");
}
/*
** Copy the columns from the temp row to the base row.
** The base row has fewer columns than the temp row,
** because it doesn't contain the row location.
*/
RowUtil.copyRefColumns(newBaseRow, deferredTempRow2, numberOfBaseColumns);
rowChanger.updateRow(deferredBaseRow, newBaseRow, baseRowLocation);
}
} finally {
sourceResultSet.clearCurrentRow();
rs.close();
}
}
}
use of org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo in project derby by apache.
the class ConstraintConstantAction method validateConstraint.
/**
* Evaluate a check constraint or not null column constraint.
* Generate a query of the
* form SELECT COUNT(*) FROM t where NOT(<check constraint>)
* and run it by compiling and executing it. Will
* work ok if the table is empty and query returns null.
*
* @param constraintName constraint name
* @param constraintText constraint text
* @param constraintId constraint id
* @param td referenced table
* @param lcc the language connection context
* @param isCheckConstraint the constraint is a check constraint
* @param isInitiallyDeferred {@code true} if the constraint is
* initially deferred
*
* @return true if null constraint passes, false otherwise
*
* @exception StandardException if check constraint fails
*/
static boolean validateConstraint(String constraintName, String constraintText, UUID constraintId, TableDescriptor td, LanguageConnectionContext lcc, boolean isCheckConstraint, boolean isInitiallyDeferred) throws StandardException {
StringBuilder checkStmt = new StringBuilder();
/* should not use select sum(not(<check-predicate>) ? 1: 0) because
* that would generate much more complicated code and may exceed Java
* limits if we have a large number of check constraints, beetle 4347
*/
checkStmt.append("SELECT COUNT(*) FROM ");
checkStmt.append(td.getQualifiedName());
checkStmt.append(" WHERE NOT(");
checkStmt.append(constraintText);
checkStmt.append(")");
ResultSet rs = null;
try {
PreparedStatement ps = lcc.prepareInternalStatement(checkStmt.toString());
// This is a substatement; for now, we do not set any timeout
// for it. We might change this behaviour later, by linking
// timeout to its parent statement's timeout settings.
rs = ps.executeSubStatement(lcc, false, 0L);
ExecRow row = rs.getNextRow();
if (SanityManager.DEBUG) {
if (row == null) {
SanityManager.THROWASSERT("did not get any rows back from query: " + checkStmt.toString());
}
}
Number value = ((Number) ((NumberDataValue) row.getRowArray()[0]).getObject());
/*
** Value may be null if there are no rows in the
** table.
*/
if ((value != null) && (value.longValue() != 0)) {
// check constraint is violated.
if (isCheckConstraint) {
if (isInitiallyDeferred) {
// Remember the violation
List<UUID> violatingConstraints = new ArrayList<UUID>();
violatingConstraints.add(constraintId);
// FIXME: We don't know the row locations of the
// violating rows, so for now, just pretend we know one,
// then invalidate the row location information forcing
// full table check at validation time
CheckInfo[] newCi = new CheckInfo[1];
DeferredConstraintsMemory.rememberCheckViolations(lcc, td.getObjectID(), td.getSchemaName(), td.getName(), null, violatingConstraints, new HeapRowLocation(), /* dummy */
newCi);
newCi[0].setInvalidatedRowLocations();
} else {
throw StandardException.newException(SQLState.LANG_ADD_CHECK_CONSTRAINT_FAILED, constraintName, td.getQualifiedName(), value.toString());
}
}
/*
* for not null constraint violations exception will be thrown in caller
* check constraint will not get here since exception is thrown
* above
*/
return false;
}
} finally {
if (rs != null) {
rs.close();
}
}
return true;
}
Aggregations