use of org.apache.derby.iapi.sql.dictionary.TriggerDescriptor in project derby by apache.
the class UpdateNode method getUpdateReadMap.
/**
* Builds a bitmap of all columns which should be read from the
* Store in order to satisfy an UPDATE statement.
*
* Is passed a list of updated columns. Does the following:
*
* 1) finds all indices which overlap the updated columns
* 2) adds the index columns to a bitmap of affected columns
* 3) adds the index descriptors to a list of conglomerate
* descriptors.
* 4) finds all constraints which overlap the updated columns
* and adds the constrained columns to the bitmap
* 5) finds all triggers which overlap the updated columns.
* 6) Go through all those triggers from step 5 and for each one of
* those triggers, follow the rules below to decide which columns
* should be read.
* Rule1)If trigger column information is null, then read all the
* columns from trigger table into memory irrespective of whether
* there is any trigger action column information. 2 egs of such
* triggers
* create trigger tr1 after update on t1 for each row values(1);
* create trigger tr1 after update on t1 referencing old as oldt
* for each row insert into t2 values(2,oldt.j,-2);
* Rule2)If trigger column information is available but no trigger
* action column information is found and no REFERENCES clause is
* used for the trigger, then read all the columns identified by
* the trigger column. eg
* create trigger tr1 after update of c1 on t1
* for each row values(1);
* Rule3)If trigger column information and trigger action column
* information both are not null, then only those columns will be
* read into memory. This is possible only for triggers created in
* release 10.9 or higher(with the exception of 10.7.1.1 where we
* did collect that information but because of corruption caused
* by those changes, we do not use the information collected by
* 10.7). Starting 10.9, we are collecting trigger action column
* informatoin so we can be smart about what columns get read
* during trigger execution. eg
* create trigger tr1 after update of c1 on t1
* referencing old as oldt for each row
* insert into t2 values(2,oldt.j,-2);
* Rule4)If trigger column information is available but no trigger
* action column information is found but REFERENCES clause is used
* for the trigger, then read all the columns from the trigger
* table. This will cover soft-upgrade scenario for triggers created
* pre-10.9.
* eg trigger created prior to 10.9
* create trigger tr1 after update of c1 on t1
* referencing old as oldt for each row
* insert into t2 values(2,oldt.j,-2);
* 7) adds the triggers to an evolving list of triggers
* 8) finds all generated columns whose generation clauses mention
* the updated columns and adds all of the mentioned columns
*
* @param dd Data Dictionary
* @param baseTable Table on which update is issued
* @param updateColumnList a list of updated columns
* @param conglomerates OUT: list of affected indices
* @param relevantConstraints IN/OUT. Empty list is passed in. We hang constraints on it as we go.
* @param relevantTriggers IN/OUT. Passed in as an empty list. Filled in as we go.
* @param needsDeferredProcessing IN/OUT. true if the statement already needs
* deferred processing. set while evaluating this
* routine if a trigger or constraint requires
* deferred processing
* @param affectedGeneratedColumns columns whose generation clauses mention updated columns
*
* @return a FormatableBitSet of columns to be read out of the base table
*
* @exception StandardException Thrown on error
*/
static FormatableBitSet getUpdateReadMap(DataDictionary dd, TableDescriptor baseTable, ResultColumnList updateColumnList, List<ConglomerateDescriptor> conglomerates, ConstraintDescriptorList relevantConstraints, TriggerDescriptorList relevantTriggers, boolean[] needsDeferredProcessing, ColumnDescriptorList affectedGeneratedColumns) throws StandardException {
if (SanityManager.DEBUG) {
SanityManager.ASSERT(updateColumnList != null, "updateColumnList is null");
}
int columnCount = baseTable.getMaxColumnID();
FormatableBitSet columnMap = new FormatableBitSet(columnCount + 1);
/*
** Add all the changed columns. We don't strictly
** need the before image of the changed column in all cases,
** but it makes life much easier since things are set
** up around the assumption that we have the before
** and after image of the column.
*/
int[] changedColumnIds = updateColumnList.sortMe();
for (int ix = 0; ix < changedColumnIds.length; ix++) {
columnMap.set(changedColumnIds[ix]);
}
/*
** Get a list of the indexes that need to be
** updated. ColumnMap contains all indexed
** columns where 1 or more columns in the index
** are going to be modified.
*/
DMLModStatementNode.getXAffectedIndexes(baseTable, updateColumnList, columnMap, conglomerates);
/*
** Add all columns needed for constraints. We don't
** need to bother with foreign key/primary key constraints
** because they are added as a side effect of adding
** their indexes above.
*/
baseTable.getAllRelevantConstraints(StatementType.UPDATE, changedColumnIds, needsDeferredProcessing, relevantConstraints);
int rclSize = relevantConstraints.size();
for (int index = 0; index < rclSize; index++) {
ConstraintDescriptor cd = relevantConstraints.elementAt(index);
if (cd.getConstraintType() != DataDictionary.CHECK_CONSTRAINT) {
continue;
}
int[] refColumns = ((CheckConstraintDescriptor) cd).getReferencedColumns();
for (int i = 0; i < refColumns.length; i++) {
columnMap.set(refColumns[i]);
}
}
//
// Add all columns mentioned by generation clauses which are affected
// by the columns being updated.
//
addGeneratedColumnPrecursors(baseTable, affectedGeneratedColumns, columnMap);
/*
* If we have any UPDATE triggers, then we will follow the 4 rules
* mentioned in the comments at the method level.
*/
baseTable.getAllRelevantTriggers(StatementType.UPDATE, changedColumnIds, relevantTriggers);
if (relevantTriggers.size() > 0) {
needsDeferredProcessing[0] = true;
boolean needToIncludeAllColumns = false;
// If we are dealing with database created in 10.8 and prior,
// then we must be in soft upgrade mode. For such databases,
// we do not want to do any column reading optimization.
//
// For triggers created in 10.7.1.1, we kept track of trigger
// action columns used through the REFERENCING clause. That
// information was gathered so we could be smart about what
// columns from trigger table should be read during trigger
// execution. But those changes in code resulted in data
// corruption DERBY-5121. Because of that, we took out the
// column read optimization changes from codeline for next
// release of 10.7 and 10.8 codeline.
// But we can still have triggers created in 10.7.1.1 with
// trigger action column information in SYSTRIGGERS.
// In 10.9, we are reimplementing what columns should be read
// from the trigger table during trigger execution. But we do
// not want this column optimization changes to be used in soft
// upgrade mode for a 10.8 or prior database so that we can
// go back to the older release if that's what the user chooses
// after the soft-upgrade.
boolean in10_9_orHigherVersion = dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_9, null);
for (TriggerDescriptor trd : relevantTriggers) {
if (in10_9_orHigherVersion) {
// See if we can avoid reading all the columns from the
// trigger table.
int[] referencedColsInTriggerAction = trd.getReferencedColsInTriggerAction();
int[] triggerCols = trd.getReferencedCols();
if (triggerCols == null || triggerCols.length == 0) {
for (int i = 0; i < columnCount; i++) {
columnMap.set(i + 1);
}
// going to read all the columns anyways.
break;
} else {
if (referencedColsInTriggerAction == null || referencedColsInTriggerAction.length == 0) {
// Does this trigger have REFERENCING clause defined on it
if (!trd.getReferencingNew() && !trd.getReferencingOld()) {
// trigger columns
for (int ix = 0; ix < triggerCols.length; ix++) {
columnMap.set(triggerCols[ix]);
}
} else {
// The trigger has REFERENCING clause defined on it
// so it might be used them in trigger action.
// We should just go ahead and read all the
// columns from the trigger table. Now, there is
// no need to go through the rest of the triggers
// because we are going to read all the columns
// anyways.
needToIncludeAllColumns = true;
break;
}
} else {
// trigger table for the trigger execution.
for (int ix = 0; ix < triggerCols.length; ix++) {
columnMap.set(triggerCols[ix]);
}
for (int ix = 0; ix < referencedColsInTriggerAction.length; ix++) {
columnMap.set(referencedColsInTriggerAction[ix]);
}
}
}
} else {
// Does this trigger have REFERENCING clause defined on it
if (!trd.getReferencingNew() && !trd.getReferencingOld())
continue;
else {
needToIncludeAllColumns = true;
break;
}
}
}
if (needToIncludeAllColumns) {
for (int i = 1; i <= columnCount; i++) {
columnMap.set(i);
}
}
}
return columnMap;
}
Aggregations