use of org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor in project derby by apache.
the class DataDictionaryImpl method addConstraintDescriptor.
/**
* Adds the given ConstraintDescriptor to the data dictionary,
* associated with the given table and constraint type.
*
* @param descriptor The descriptor to add
* @param tc The transaction controller
*
* @exception StandardException Thrown on error
*/
public void addConstraintDescriptor(ConstraintDescriptor descriptor, TransactionController tc) throws StandardException {
int type = descriptor.getConstraintType();
if (SanityManager.DEBUG) {
if (!(type == DataDictionary.PRIMARYKEY_CONSTRAINT || type == DataDictionary.FOREIGNKEY_CONSTRAINT || type == DataDictionary.UNIQUE_CONSTRAINT || type == DataDictionary.CHECK_CONSTRAINT)) {
SanityManager.THROWASSERT("constraint type (" + type + ") is unexpected value");
}
}
addDescriptor(descriptor, descriptor.getSchemaDescriptor(), SYSCONSTRAINTS_CATALOG_NUM, false, tc);
switch(type) {
case DataDictionary.PRIMARYKEY_CONSTRAINT:
case DataDictionary.FOREIGNKEY_CONSTRAINT:
case DataDictionary.UNIQUE_CONSTRAINT:
if (SanityManager.DEBUG) {
if (!(descriptor instanceof KeyConstraintDescriptor)) {
SanityManager.THROWASSERT("descriptor expected to be instanceof KeyConstraintDescriptor, " + "not, " + descriptor.getClass().getName());
}
}
addSubKeyConstraint((KeyConstraintDescriptor) descriptor, tc);
break;
case DataDictionary.CHECK_CONSTRAINT:
if (SanityManager.DEBUG) {
if (!(descriptor instanceof CheckConstraintDescriptor)) {
SanityManager.THROWASSERT("descriptor expected " + "to be instanceof CheckConstraintDescriptorImpl, " + "not, " + descriptor.getClass().getName());
}
}
addDescriptor(descriptor, null, SYSCHECKS_CATALOG_NUM, true, tc);
break;
}
}
use of org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor in project derby by apache.
the class SYSCHECKSRowFactory method makeRow.
// ///////////////////////////////////////////////////////////////////////////
//
// METHODS
//
// ///////////////////////////////////////////////////////////////////////////
/**
* Make a SYSCHECKS row
*
* @param td CheckConstraintDescriptorImpl
*
* @return Row suitable for inserting into SYSCHECKS.
*
* @exception StandardException thrown on failure
*/
public ExecRow makeRow(TupleDescriptor td, TupleDescriptor parent) throws StandardException {
DataValueDescriptor col;
ExecIndexRow row;
ReferencedColumns rcd = null;
String checkDefinition = null;
String constraintID = null;
if (td != null) {
CheckConstraintDescriptor cd = (CheckConstraintDescriptor) td;
/*
** We only allocate a new UUID if the descriptor doesn't already have one.
** For descriptors replicated from a Source system, we already have an UUID.
*/
constraintID = cd.getUUID().toString();
checkDefinition = cd.getConstraintText();
rcd = cd.getReferencedColumnsDescriptor();
}
/* Build the row */
row = getExecutionFactory().getIndexableRow(SYSCHECKS_COLUMN_COUNT);
/* 1st column is CONSTRAINTID (UUID - char(36)) */
row.setColumn(SYSCHECKS_CONSTRAINTID, new SQLChar(constraintID));
/* 2nd column is CHECKDEFINITION */
row.setColumn(SYSCHECKS_CHECKDEFINITION, dvf.getLongvarcharDataValue(checkDefinition));
/* 3rd column is REFERENCEDCOLUMNS
* (user type org.apache.derby.catalog.ReferencedColumns)
*/
row.setColumn(SYSCHECKS_REFERENCEDCOLUMNS, new UserType(rcd));
return row;
}
use of org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor in project derby by apache.
the class AlterTableConstantAction method dropColumnFromTable.
/**
* Workhorse for dropping a column from a table.
*
* This routine drops a column from a table, taking care
* to properly handle the various related schema objects.
*
* The syntax which gets you here is:
*
* ALTER TABLE tbl DROP [COLUMN] col [CASCADE|RESTRICT]
*
* The keyword COLUMN is optional, and if you don't
* specify CASCADE or RESTRICT, the default is CASCADE
* (the default is chosen in the parser, not here).
*
* If you specify RESTRICT, then the column drop should be
* rejected if it would cause a dependent schema object
* to become invalid.
*
* If you specify CASCADE, then the column drop should
* additionally drop other schema objects which have
* become invalid.
*
* You may not drop the last (only) column in a table.
*
* Schema objects of interest include:
* - views
* - triggers
* - constraints
* - check constraints
* - primary key constraints
* - foreign key constraints
* - unique key constraints
* - not null constraints
* - privileges
* - indexes
* - default values
*
* Dropping a column may also change the column position
* numbers of other columns in the table, which may require
* fixup of schema objects (such as triggers and column
* privileges) which refer to columns by column position number.
*
* Indexes are a bit interesting. The official SQL spec
* doesn't talk about indexes; they are considered to be
* an imlementation-specific performance optimization.
* The current Derby behavior is that:
* - CASCADE/RESTRICT doesn't matter for indexes
* - when a column is dropped, it is removed from any indexes
* which contain it.
* - if that column was the only column in the index, the
* entire index is dropped.
*
* @param columnName the name of the column specfication in the ALTER
* statement-- currently we allow only one.
* @exception StandardException thrown on failure.
*/
private void dropColumnFromTable(String columnName) throws StandardException {
boolean cascade = (behavior == StatementType.DROP_CASCADE);
// drop any generated columns which reference this column
ColumnDescriptorList generatedColumnList = td.getGeneratedColumns();
int generatedColumnCount = generatedColumnList.size();
ArrayList<String> cascadedDroppedColumns = new ArrayList<String>();
for (int i = 0; i < generatedColumnCount; i++) {
ColumnDescriptor generatedColumn = generatedColumnList.elementAt(i);
String[] referencedColumnNames = generatedColumn.getDefaultInfo().getReferencedColumnNames();
int referencedColumnCount = referencedColumnNames.length;
for (int j = 0; j < referencedColumnCount; j++) {
if (columnName.equals(referencedColumnNames[j])) {
String generatedColumnName = generatedColumn.getColumnName();
// we're trying to drop
if (!cascade) {
//
throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, dm.getActionString(DependencyManager.DROP_COLUMN), columnName, "GENERATED COLUMN", generatedColumnName);
} else {
cascadedDroppedColumns.add(generatedColumnName);
}
}
}
}
DataDescriptorGenerator ddg = dd.getDataDescriptorGenerator();
int cascadedDrops = cascadedDroppedColumns.size();
int sizeAfterCascadedDrops = td.getColumnDescriptorList().size() - cascadedDrops;
// can NOT drop a column if it is the only one in the table
if (sizeAfterCascadedDrops == 1) {
throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, dm.getActionString(DependencyManager.DROP_COLUMN), "THE *LAST* COLUMN " + columnName, "TABLE", td.getQualifiedName());
}
// now drop dependent generated columns
for (int i = 0; i < cascadedDrops; i++) {
String generatedColumnName = cascadedDroppedColumns.get(i);
activation.addWarning(StandardException.newWarning(SQLState.LANG_GEN_COL_DROPPED, generatedColumnName, td.getName()));
//
// We can only recurse 2 levels since a generation clause cannot
// refer to other generated columns.
//
dropColumnFromTable(generatedColumnName);
}
/*
* Cascaded drops of dependent generated columns may require us to
* rebuild the table descriptor.
*/
td = dd.getTableDescriptor(tableId);
ColumnDescriptor columnDescriptor = td.getColumnDescriptor(columnName);
// We already verified this in bind, but do it again
if (columnDescriptor == null) {
throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, columnName, td.getQualifiedName());
}
int size = td.getColumnDescriptorList().size();
droppedColumnPosition = columnDescriptor.getPosition();
FormatableBitSet toDrop = new FormatableBitSet(size + 1);
toDrop.set(droppedColumnPosition);
td.setReferencedColumnMap(toDrop);
dm.invalidateFor(td, (cascade ? DependencyManager.DROP_COLUMN : DependencyManager.DROP_COLUMN_RESTRICT), lcc);
// If column has a default we drop the default and any dependencies
if (columnDescriptor.getDefaultInfo() != null) {
dm.clearDependencies(lcc, columnDescriptor.getDefaultDescriptor(dd));
}
// then we need to drop the system-generated sequence backing it.
if (columnDescriptor.isAutoincrement() && dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_11, null)) {
DropTableConstantAction.dropIdentitySequence(dd, td, activation);
}
// columns which are used through REFERENCING clause
for (TriggerDescriptor trd : dd.getTriggerDescriptors(td)) {
// If we find that the trigger is dependent on the column being
// dropped because column is part of trigger columns list, then
// we will give a warning or drop the trigger based on whether
// ALTER TABLE DROP COLUMN is RESTRICT or CASCADE. In such a
// case, no need to check if the trigger action columns referenced
// through REFERENCING clause also used the column being dropped.
boolean triggerDroppedAlready = false;
int[] referencedCols = trd.getReferencedCols();
if (referencedCols != null) {
int refColLen = referencedCols.length, j;
boolean changed = false;
for (j = 0; j < refColLen; j++) {
if (referencedCols[j] > droppedColumnPosition) {
// Trigger is not defined on the column being dropped
// but the column position of trigger column is changing
// because the position of the column being dropped is
// before the the trigger column
changed = true;
} else if (referencedCols[j] == droppedColumnPosition) {
// the trigger is defined on the column being dropped
if (cascade) {
trd.drop(lcc);
triggerDroppedAlready = true;
activation.addWarning(StandardException.newWarning(SQLState.LANG_TRIGGER_DROPPED, trd.getName(), td.getName()));
} else {
// otherwsie there would be unexpected behaviors
throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, dm.getActionString(DependencyManager.DROP_COLUMN), columnName, "TRIGGER", trd.getName());
}
break;
}
}
// drop column.
if (j == refColLen && changed) {
dd.dropTriggerDescriptor(trd, tc);
for (j = 0; j < refColLen; j++) {
if (referencedCols[j] > droppedColumnPosition)
referencedCols[j]--;
}
trd.setReferencedCols(referencedCols);
dd.addDescriptor(trd, sd, DataDictionary.SYSTRIGGERS_CATALOG_NUM, false, tc);
}
}
// loop above, then move to next trigger
if (triggerDroppedAlready)
continue;
// Column being dropped is not one of trigger columns. Check if
// that column is getting used inside the trigger action through
// REFERENCING clause. This can be tracked only for triggers
// created in 10.7 and higher releases. Derby releases prior to
// that did not keep track of trigger action columns used
// through the REFERENCING clause.
int[] referencedColsInTriggerAction = trd.getReferencedColsInTriggerAction();
if (referencedColsInTriggerAction != null) {
int refColInTriggerActionLen = referencedColsInTriggerAction.length, j;
boolean changedColPositionInTriggerAction = false;
for (j = 0; j < refColInTriggerActionLen; j++) {
if (referencedColsInTriggerAction[j] > droppedColumnPosition) {
changedColPositionInTriggerAction = true;
} else if (referencedColsInTriggerAction[j] == droppedColumnPosition) {
if (cascade) {
trd.drop(lcc);
triggerDroppedAlready = true;
activation.addWarning(StandardException.newWarning(SQLState.LANG_TRIGGER_DROPPED, trd.getName(), td.getName()));
} else {
// we'd better give an error if don't drop it,
throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, dm.getActionString(DependencyManager.DROP_COLUMN), columnName, "TRIGGER", trd.getName());
}
break;
}
}
// column has been actually dropped from the table descriptor.
if (j == refColInTriggerActionLen && changedColPositionInTriggerAction) {
dd.dropTriggerDescriptor(trd, tc);
for (j = 0; j < refColInTriggerActionLen; j++) {
if (referencedColsInTriggerAction[j] > droppedColumnPosition)
referencedColsInTriggerAction[j]--;
}
trd.setReferencedColsInTriggerAction(referencedColsInTriggerAction);
dd.addDescriptor(trd, sd, DataDictionary.SYSTRIGGERS_CATALOG_NUM, false, tc);
}
}
}
ConstraintDescriptorList csdl = dd.getConstraintDescriptors(td);
int csdl_size = csdl.size();
ArrayList<ConstantAction> newCongloms = new ArrayList<ConstantAction>();
// we want to remove referenced primary/unique keys in the second
// round. This will ensure that self-referential constraints will
// work OK.
int tbr_size = 0;
ConstraintDescriptor[] toBeRemoved = new ConstraintDescriptor[csdl_size];
// let's go downwards, don't want to get messed up while removing
for (int i = csdl_size - 1; i >= 0; i--) {
ConstraintDescriptor cd = csdl.elementAt(i);
int[] referencedColumns = cd.getReferencedColumns();
int numRefCols = referencedColumns.length, j;
boolean changed = false;
for (j = 0; j < numRefCols; j++) {
if (referencedColumns[j] > droppedColumnPosition)
changed = true;
if (referencedColumns[j] == droppedColumnPosition)
break;
}
if (// column not referenced
j == numRefCols) {
if ((cd instanceof CheckConstraintDescriptor) && changed) {
dd.dropConstraintDescriptor(cd, tc);
for (j = 0; j < numRefCols; j++) {
if (referencedColumns[j] > droppedColumnPosition)
referencedColumns[j]--;
}
((CheckConstraintDescriptor) cd).setReferencedColumnsDescriptor(new ReferencedColumnsDescriptorImpl(referencedColumns));
dd.addConstraintDescriptor(cd, tc);
}
continue;
}
if (!cascade) {
//
throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, dm.getActionString(DependencyManager.DROP_COLUMN), columnName, "CONSTRAINT", cd.getConstraintName());
}
if (cd instanceof ReferencedKeyConstraintDescriptor) {
// restrict will raise an error in invalidate if referenced
toBeRemoved[tbr_size++] = cd;
continue;
}
// drop now in all other cases
dm.invalidateFor(cd, DependencyManager.DROP_CONSTRAINT, lcc);
dropConstraint(cd, td, newCongloms, activation, lcc, true);
activation.addWarning(StandardException.newWarning(SQLState.LANG_CONSTRAINT_DROPPED, cd.getConstraintName(), td.getName()));
}
for (int i = tbr_size - 1; i >= 0; i--) {
ConstraintDescriptor cd = toBeRemoved[i];
dropConstraint(cd, td, newCongloms, activation, lcc, false);
activation.addWarning(StandardException.newWarning(SQLState.LANG_CONSTRAINT_DROPPED, cd.getConstraintName(), td.getName()));
if (cascade) {
ConstraintDescriptorList fkcdl = dd.getForeignKeys(cd.getUUID());
for (ConstraintDescriptor fkcd : fkcdl) {
dm.invalidateFor(fkcd, DependencyManager.DROP_CONSTRAINT, lcc);
dropConstraint(fkcd, td, newCongloms, activation, lcc, true);
activation.addWarning(StandardException.newWarning(SQLState.LANG_CONSTRAINT_DROPPED, fkcd.getConstraintName(), fkcd.getTableDescriptor().getName()));
}
}
dm.invalidateFor(cd, DependencyManager.DROP_CONSTRAINT, lcc);
dm.clearDependencies(lcc, cd);
}
/* If there are new backing conglomerates which must be
* created to replace a dropped shared conglomerate
* (where the shared conglomerate was dropped as part
* of a "drop constraint" call above), then create them
* now. We do this *after* dropping all dependent
* constraints because we don't want to waste time
* creating a new conglomerate if it's just going to be
* dropped again as part of another "drop constraint".
*/
createNewBackingCongloms(newCongloms, (long[]) null);
/*
* The work we've done above, specifically the possible
* dropping of primary key, foreign key, and unique constraints
* and their underlying indexes, may have affected the table
* descriptor. By re-reading the table descriptor here, we
* ensure that the compressTable code is working with an
* accurate table descriptor. Without this line, we may get
* conglomerate-not-found errors and the like due to our
* stale table descriptor.
*/
td = dd.getTableDescriptor(tableId);
compressTable();
ColumnDescriptorList tab_cdl = td.getColumnDescriptorList();
// drop the column from syscolumns
dd.dropColumnDescriptor(td.getUUID(), columnName, tc);
ColumnDescriptor[] cdlArray = new ColumnDescriptor[size - columnDescriptor.getPosition()];
//
for (int i = columnDescriptor.getPosition(), j = 0; i < size; i++, j++) {
ColumnDescriptor cd = tab_cdl.elementAt(i);
dd.dropColumnDescriptor(td.getUUID(), cd.getColumnName(), tc);
cd.setPosition(i);
if (cd.isAutoincrement()) {
cd.setAutoinc_create_or_modify_Start_Increment(ColumnDefinitionNode.CREATE_AUTOINCREMENT);
}
cdlArray[j] = cd;
}
dd.addDescriptorArray(cdlArray, td, DataDictionary.SYSCOLUMNS_CATALOG_NUM, false, tc);
// By this time, the column has been removed from the table descriptor.
// Now, go through all the triggers and regenerate their trigger action
// SPS and rebind the generated trigger action sql. If the trigger
// action is using the dropped column, it will get detected here. If
// not, then we will have generated the internal trigger action sql
// which matches the trigger action sql provided by the user.
//
// eg of positive test case
// create table atdc_16_tab1 (a1 integer, b1 integer, c1 integer);
// create table atdc_16_tab2 (a2 integer, b2 integer, c2 integer);
// create trigger atdc_16_trigger_1
// after update of b1 on atdc_16_tab1
// REFERENCING NEW AS newt
// for each row
// update atdc_16_tab2 set c2 = newt.c1
// The internal representation for the trigger action before the column
// is dropped is as follows
// update atdc_16_tab2 set c2 =
// org.apache.derby.iapi.db.Factory::getTriggerExecutionContext().
// getONewRow().getInt(3)
// After the drop column shown as below
// alter table DERBY4998_SOFT_UPGRADE_RESTRICT drop column c11
// The above internal representation of tigger action sql is not
// correct anymore because column position of c1 in atdc_16_tab1 has
// now changed from 3 to 2. Following while loop will regenerate it and
// change it to as follows
// update atdc_16_tab2 set c2 =
// org.apache.derby.iapi.db.Factory::getTriggerExecutionContext().
// getONewRow().getInt(2)
//
// We could not do this before the actual column drop, because the
// rebind would have still found the column being dropped in the
// table descriptor and hence use of such a column in the trigger
// action rebind would not have been caught.
// For the table on which ALTER TABLE is getting performed, find out
// all the SPSDescriptors that use that table as a provider. We are
// looking for SPSDescriptors that have been created internally for
// trigger action SPSes. Through those SPSDescriptors, we will be
// able to get to the triggers dependent on the table being altered
// Following will get all the dependent objects that are using
// ALTER TABLE table as provider
List<DependencyDescriptor> depsOnAlterTableList = dd.getProvidersDescriptorList(td.getObjectID().toString());
for (DependencyDescriptor depOnAT : depsOnAlterTableList) {
// Go through all the dependent objects on the table being altered
DependableFinder dependent = depOnAT.getDependentFinder();
// stored prepared statement.
if (dependent.getSQLObjectType().equals(Dependable.STORED_PREPARED_STATEMENT)) {
// Look for all the dependent objects that are using this
// stored prepared statement as provider. We are only
// interested in dependents that are triggers.
List<DependencyDescriptor> depsTrigger = dd.getProvidersDescriptorList(depOnAT.getUUID().toString());
for (DependencyDescriptor depsTriggerDesc : depsTrigger) {
DependableFinder providerIsTrigger = depsTriggerDesc.getDependentFinder();
// it is a trigger
if (providerIsTrigger.getSQLObjectType().equals(Dependable.TRIGGER)) {
// Drop and recreate the trigger after regenerating
// it's trigger action plan. If the trigger action
// depends on the column being dropped, it will be
// caught here.
TriggerDescriptor trdToBeDropped = dd.getTriggerDescriptor(depsTriggerDesc.getUUID());
// First check for dependencies in the trigger's WHEN
// clause, if there is one.
UUID whenClauseId = trdToBeDropped.getWhenClauseId();
boolean gotDropped = false;
if (whenClauseId != null) {
gotDropped = columnDroppedAndTriggerDependencies(trdToBeDropped, whenClauseId, true, cascade, columnName);
}
// dependencies.
if (!gotDropped) {
columnDroppedAndTriggerDependencies(trdToBeDropped, trdToBeDropped.getActionId(), false, cascade, columnName);
}
}
}
}
}
// Adjust the column permissions rows in SYSCOLPERMS to reflect the
// changed column positions due to the dropped column:
dd.updateSYSCOLPERMSforDropColumn(td.getUUID(), tc, columnDescriptor);
// remove column descriptor from table descriptor. this fixes up the
// list in case we were called recursively in order to cascade-drop a
// dependent generated column.
tab_cdl.remove(td.getColumnDescriptor(columnName));
}
use of org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor 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