Search in sources :

Example 1 with CheckConstraintDescriptor

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;
    }
}
Also used : ReferencedKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor) KeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.KeyConstraintDescriptor) SubKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.SubKeyConstraintDescriptor) ForeignKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor) CheckConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor) SubCheckConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.SubCheckConstraintDescriptor) SQLLongint(org.apache.derby.iapi.types.SQLLongint)

Example 2 with CheckConstraintDescriptor

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;
}
Also used : ReferencedColumns(org.apache.derby.catalog.ReferencedColumns) SQLChar(org.apache.derby.iapi.types.SQLChar) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor) CheckConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor) SubCheckConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.SubCheckConstraintDescriptor) ExecIndexRow(org.apache.derby.iapi.sql.execute.ExecIndexRow) UserType(org.apache.derby.iapi.types.UserType)

Example 3 with CheckConstraintDescriptor

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));
}
Also used : DependencyDescriptor(org.apache.derby.iapi.sql.dictionary.DependencyDescriptor) ArrayList(java.util.ArrayList) ReferencedColumnsDescriptorImpl(org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl) CheckConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor) DataDescriptorGenerator(org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator) ConstantAction(org.apache.derby.iapi.sql.execute.ConstantAction) DependableFinder(org.apache.derby.catalog.DependableFinder) ColumnDescriptorList(org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet) UUID(org.apache.derby.catalog.UUID) ColumnDescriptor(org.apache.derby.iapi.sql.dictionary.ColumnDescriptor) ConstraintDescriptorList(org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList) TriggerDescriptor(org.apache.derby.iapi.sql.dictionary.TriggerDescriptor) CheckConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor) ForeignKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor) ConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor) ReferencedKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor) ReferencedKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor)

Example 4 with CheckConstraintDescriptor

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;
}
Also used : CheckConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor) ConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet) CheckConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor) TriggerDescriptor(org.apache.derby.iapi.sql.dictionary.TriggerDescriptor)

Aggregations

CheckConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor)4 FormatableBitSet (org.apache.derby.iapi.services.io.FormatableBitSet)2 ConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor)2 ForeignKeyConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor)2 ReferencedKeyConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor)2 SubCheckConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.SubCheckConstraintDescriptor)2 TriggerDescriptor (org.apache.derby.iapi.sql.dictionary.TriggerDescriptor)2 ArrayList (java.util.ArrayList)1 DependableFinder (org.apache.derby.catalog.DependableFinder)1 ReferencedColumns (org.apache.derby.catalog.ReferencedColumns)1 UUID (org.apache.derby.catalog.UUID)1 ReferencedColumnsDescriptorImpl (org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl)1 ColumnDescriptor (org.apache.derby.iapi.sql.dictionary.ColumnDescriptor)1 ColumnDescriptorList (org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList)1 ConstraintDescriptorList (org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList)1 DataDescriptorGenerator (org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator)1 DependencyDescriptor (org.apache.derby.iapi.sql.dictionary.DependencyDescriptor)1 KeyConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.KeyConstraintDescriptor)1 SubKeyConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.SubKeyConstraintDescriptor)1 ConstantAction (org.apache.derby.iapi.sql.execute.ConstantAction)1