Search in sources :

Example 6 with ReferencedKeyConstraintDescriptor

use of org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor 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 7 with ReferencedKeyConstraintDescriptor

use of org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor in project derby by apache.

the class AlterTableConstantAction method truncateTable.

/* 
	 * TRUNCATE TABLE  TABLENAME; (quickly removes all the rows from table and
	 * it's correctponding indexes).
	 * Truncate is implemented by dropping the existing conglomerates(heap,indexes) and recreating a
	 * new ones  with the properties of dropped conglomerates. Currently Store
	 * does not have support to truncate existing conglomerated until store
	 * supports it , this is the only way to do it.
	 * Error Cases: Truncate error cases same as other DDL's statements except
	 * 1)Truncate is not allowed when the table is references by another table.
	 * 2)Truncate is not allowed when there are enabled delete triggers on the table.
	 * Note: Because conglomerate number is changed during recreate process all the statements will be
	 * marked as invalide and they will get recompiled internally on their next
	 * execution. This is okay because truncate makes the number of rows to zero
	 * it may be good idea to recompile them becuase plans are likely to be
	 * incorrect. Recompile is done internally by Derby, user does not have
	 * any effect.
	 */
private void truncateTable() throws StandardException {
    ExecRow emptyHeapRow;
    long newHeapConglom;
    Properties properties = new Properties();
    RowLocation rl;
    if (SanityManager.DEBUG) {
        if (lockGranularity != '\0') {
            SanityManager.THROWASSERT("lockGranularity expected to be '\0', not " + lockGranularity);
        }
        SanityManager.ASSERT(columnInfo == null, "columnInfo expected to be null");
        SanityManager.ASSERT(constraintActions == null, "constraintActions expected to be null");
    }
    // and the ON DELETE action is NO ACTION.
    for (ConstraintDescriptor cd : dd.getConstraintDescriptors(td)) {
        if (cd instanceof ReferencedKeyConstraintDescriptor) {
            final ReferencedKeyConstraintDescriptor rfcd = (ReferencedKeyConstraintDescriptor) cd;
            for (ConstraintDescriptor fkcd : rfcd.getNonSelfReferencingFK(ConstraintDescriptor.ENABLED)) {
                final ForeignKeyConstraintDescriptor fk = (ForeignKeyConstraintDescriptor) fkcd;
                throw StandardException.newException(SQLState.LANG_NO_TRUNCATE_ON_FK_REFERENCE_TABLE, td.getName());
            }
        }
    }
    // truncate is not allowed when there are enabled DELETE triggers
    for (TriggerDescriptor trd : dd.getTriggerDescriptors(td)) {
        if (trd.listensForEvent(TriggerDescriptor.TRIGGER_EVENT_DELETE) && trd.isEnabled()) {
            throw StandardException.newException(SQLState.LANG_NO_TRUNCATE_ON_ENABLED_DELETE_TRIGGERS, td.getName(), trd.getName());
        }
    }
    // gather information from the existing conglomerate to create new one.
    emptyHeapRow = td.getEmptyExecRow();
    compressHeapCC = tc.openConglomerate(td.getHeapConglomerateId(), false, TransactionController.OPENMODE_FORUPDATE, TransactionController.MODE_TABLE, TransactionController.ISOLATION_SERIALIZABLE);
    rl = compressHeapCC.newRowLocationTemplate();
    // Get the properties on the old heap
    compressHeapCC.getInternalTablePropertySet(properties);
    compressHeapCC.close();
    compressHeapCC = null;
    // create new conglomerate
    newHeapConglom = tc.createConglomerate("heap", emptyHeapRow.getRowArray(), // column sort order - not required for heap
    null, td.getColumnCollationIds(), properties, TransactionController.IS_DEFAULT);
    /* Set up index info to perform truncate on them*/
    getAffectedIndexes();
    if (numIndexes > 0) {
        indexRows = new ExecIndexRow[numIndexes];
        ordering = new ColumnOrdering[numIndexes][];
        collation = new int[numIndexes][];
        for (int index = 0; index < numIndexes; index++) {
            IndexRowGenerator curIndex = compressIRGs[index];
            // create a single index row template for each index
            indexRows[index] = curIndex.getIndexRowTemplate();
            curIndex.getIndexRow(emptyHeapRow, rl, indexRows[index], (FormatableBitSet) null);
            /* For non-unique indexes, we order by all columns + the RID.
				 * For unique indexes, we just order by the columns.
				 * No need to try to enforce uniqueness here as
				 * index should be valid.
				 */
            int[] baseColumnPositions = curIndex.baseColumnPositions();
            boolean[] isAscending = curIndex.isAscending();
            int numColumnOrderings;
            numColumnOrderings = baseColumnPositions.length + 1;
            ordering[index] = new ColumnOrdering[numColumnOrderings];
            collation[index] = curIndex.getColumnCollationIds(td.getColumnDescriptorList());
            for (int ii = 0; ii < numColumnOrderings - 1; ii++) {
                ordering[index][ii] = new IndexColumnOrder(ii, isAscending[ii]);
            }
            ordering[index][numColumnOrderings - 1] = new IndexColumnOrder(numColumnOrderings - 1);
        }
    }
    /*
		** Inform the data dictionary that we are about to write to it.
		** There are several calls to data dictionary "get" methods here
		** that might be done in "read" mode in the data dictionary, but
		** it seemed safer to do this whole operation in "write" mode.
		**
		** We tell the data dictionary we're done writing at the end of
		** the transaction.
		*/
    dd.startWriting(lcc);
    // truncate  all indexes
    if (numIndexes > 0) {
        long[] newIndexCongloms = new long[numIndexes];
        for (int index = 0; index < numIndexes; index++) {
            updateIndex(newHeapConglom, dd, index, newIndexCongloms);
        }
    }
    // Update the DataDictionary
    // Get the ConglomerateDescriptor for the heap
    long oldHeapConglom = td.getHeapConglomerateId();
    ConglomerateDescriptor cd = td.getConglomerateDescriptor(oldHeapConglom);
    // Update sys.sysconglomerates with new conglomerate #
    dd.updateConglomerateDescriptor(cd, newHeapConglom, tc);
    // Now that the updated information is available in the system tables,
    // we should invalidate all statements that use the old conglomerates
    dm.invalidateFor(td, DependencyManager.TRUNCATE_TABLE, lcc);
    // Drop the old conglomerate
    tc.dropConglomerate(oldHeapConglom);
    cleanUp();
}
Also used : Properties(java.util.Properties) ForeignKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor) ConglomerateDescriptor(org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor) TriggerDescriptor(org.apache.derby.iapi.sql.dictionary.TriggerDescriptor) IndexRowGenerator(org.apache.derby.iapi.sql.dictionary.IndexRowGenerator) 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) ExecRow(org.apache.derby.iapi.sql.execute.ExecRow) ReferencedKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor) RowLocation(org.apache.derby.iapi.types.RowLocation)

Example 8 with ReferencedKeyConstraintDescriptor

use of org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor in project derby by apache.

the class DropConstraintConstantAction method executeConstantAction.

// INTERFACE METHODS
/**
 *	This is the guts of the Execution-time logic for DROP CONSTRAINT.
 *
 *	@see ConstantAction#executeConstantAction
 *
 * @exception StandardException		Thrown on failure
 */
public void executeConstantAction(Activation activation) throws StandardException {
    ConstraintDescriptor conDesc = null;
    TableDescriptor td;
    UUID indexId = null;
    String indexUUIDString;
    LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
    DataDictionary dd = lcc.getDataDictionary();
    DependencyManager dm = dd.getDependencyManager();
    TransactionController tc = lcc.getTransactionExecute();
    /*
		** Inform the data dictionary that we are about to write to it.
		** There are several calls to data dictionary "get" methods here
		** that might be done in "read" mode in the data dictionary, but
		** it seemed safer to do this whole operation in "write" mode.
		**
		** We tell the data dictionary we're done writing at the end of
		** the transaction.
		*/
    dd.startWriting(lcc);
    td = dd.getTableDescriptor(tableId);
    if (td == null) {
        throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION, tableName);
    }
    /* Table gets locked in AlterTableConstantAction */
    /*
		** If the schema descriptor is null, then
		** we must have just read ourselves in.  
		** So we will get the corresponding schema
		** descriptor from the data dictionary.
		*/
    SchemaDescriptor tdSd = td.getSchemaDescriptor();
    SchemaDescriptor constraintSd = constraintSchemaName == null ? tdSd : dd.getSchemaDescriptor(constraintSchemaName, tc, true);
    /* Get the constraint descriptor for the index, along
		 * with an exclusive row lock on the row in sys.sysconstraints
		 * in order to ensure that no one else compiles against the
		 * index.
		 */
    if (// this means "alter table drop primary key"
    constraintName == null)
        conDesc = dd.getConstraintDescriptors(td).getPrimaryKey();
    else
        conDesc = dd.getConstraintDescriptorByName(td, constraintSd, constraintName, true);
    // Error if constraint doesn't exist
    if (conDesc == null) {
        String errorName = constraintName == null ? "PRIMARY KEY" : (constraintSd.getSchemaName() + "." + constraintName);
        throw StandardException.newException(SQLState.LANG_DROP_OR_ALTER_NON_EXISTING_CONSTRAINT, errorName, td.getQualifiedName());
    }
    switch(verifyType) {
        case DataDictionary.UNIQUE_CONSTRAINT:
            if (conDesc.getConstraintType() != verifyType)
                throw StandardException.newException(SQLState.LANG_DROP_CONSTRAINT_TYPE, constraintName, "UNIQUE");
            break;
        case DataDictionary.CHECK_CONSTRAINT:
            if (conDesc.getConstraintType() != verifyType)
                throw StandardException.newException(SQLState.LANG_DROP_CONSTRAINT_TYPE, constraintName, "CHECK");
            break;
        case DataDictionary.FOREIGNKEY_CONSTRAINT:
            if (conDesc.getConstraintType() != verifyType)
                throw StandardException.newException(SQLState.LANG_DROP_CONSTRAINT_TYPE, constraintName, "FOREIGN KEY");
            break;
    }
    boolean cascadeOnRefKey = (cascade && conDesc instanceof ReferencedKeyConstraintDescriptor);
    if (!cascadeOnRefKey) {
        dm.invalidateFor(conDesc, DependencyManager.DROP_CONSTRAINT, lcc);
    }
    /*
		** If we had a primary/unique key and it is drop cascade,	
		** drop all the referencing keys now.  We MUST do this AFTER
		** dropping the referenced key because otherwise we would
		** be repeatedly changing the reference count of the referenced
		** key and generating unnecessary I/O.
		*/
    dropConstraint(conDesc, activation, lcc, !cascadeOnRefKey);
    if (cascadeOnRefKey) {
        ForeignKeyConstraintDescriptor fkcd;
        ReferencedKeyConstraintDescriptor cd;
        ConstraintDescriptorList cdl;
        cd = (ReferencedKeyConstraintDescriptor) conDesc;
        cdl = cd.getForeignKeyConstraints(ReferencedKeyConstraintDescriptor.ALL);
        int cdlSize = cdl.size();
        for (int index = 0; index < cdlSize; index++) {
            fkcd = (ForeignKeyConstraintDescriptor) cdl.elementAt(index);
            dm.invalidateFor(fkcd, DependencyManager.DROP_CONSTRAINT, lcc);
            dropConstraint(fkcd, activation, lcc, true);
        }
        /*
			** We told dropConstraintAndIndex not to
			** remove our dependencies, so send an invalidate,
			** and drop the dependencies.
			*/
        dm.invalidateFor(conDesc, DependencyManager.DROP_CONSTRAINT, lcc);
        dm.clearDependencies(lcc, conDesc);
    }
}
Also used : SchemaDescriptor(org.apache.derby.iapi.sql.dictionary.SchemaDescriptor) DependencyManager(org.apache.derby.iapi.sql.depend.DependencyManager) ConstraintDescriptorList(org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList) DataDictionary(org.apache.derby.iapi.sql.dictionary.DataDictionary) ForeignKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor) TableDescriptor(org.apache.derby.iapi.sql.dictionary.TableDescriptor) LanguageConnectionContext(org.apache.derby.iapi.sql.conn.LanguageConnectionContext) ForeignKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor) ReferencedKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor) ConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor) ReferencedKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor) UUID(org.apache.derby.catalog.UUID) TransactionController(org.apache.derby.iapi.store.access.TransactionController)

Example 9 with ReferencedKeyConstraintDescriptor

use of org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor in project derby by apache.

the class SYSFOREIGNKEYSRowFactory method makeRow.

// ///////////////////////////////////////////////////////////////////////////
// 
// METHODS
// 
// ///////////////////////////////////////////////////////////////////////////
/**
 * Make a SYSFOREIGNKEYS row
 *
 * @return	Row suitable for inserting into SYSFOREIGNKEYS.
 *
 * @exception   StandardException thrown on failure
 */
public ExecRow makeRow(TupleDescriptor td, TupleDescriptor parent) throws StandardException {
    DataValueDescriptor col;
    ExecIndexRow row;
    String constraintId = null;
    String keyConstraintId = null;
    String conglomId = null;
    String raDeleteRule = "N";
    String raUpdateRule = "N";
    if (td != null) {
        ForeignKeyConstraintDescriptor cd = (ForeignKeyConstraintDescriptor) td;
        constraintId = cd.getUUID().toString();
        ReferencedKeyConstraintDescriptor refCd = cd.getReferencedConstraint();
        if (SanityManager.DEBUG) {
            SanityManager.ASSERT(refCd != null, "this fk returned a null referenced key");
        }
        keyConstraintId = refCd.getUUID().toString();
        conglomId = cd.getIndexUUIDString();
        raDeleteRule = getRefActionAsString(cd.getRaDeleteRule());
        raUpdateRule = getRefActionAsString(cd.getRaUpdateRule());
    }
    /* Build the row  */
    row = getExecutionFactory().getIndexableRow(SYSFOREIGNKEYS_COLUMN_COUNT);
    /* 1st column is CONSTRAINTID (UUID - char(36)) */
    row.setColumn(SYSFOREIGNKEYS_CONSTRAINTID, new SQLChar(constraintId));
    /* 2nd column is CONGLOMERATEID (UUID - char(36)) */
    row.setColumn(SYSFOREIGNKEYS_CONGLOMERATEID, new SQLChar(conglomId));
    /* 3rd column is KEYCONSTRAINTID (UUID - char(36)) */
    row.setColumn(SYSFOREIGNKEYS_KEYCONSTRAINTID, new SQLChar(keyConstraintId));
    // currently, DELETERULE and UPDATERULE are always "R" for restrict
    /* 4th column is DELETERULE char(1) */
    row.setColumn(SYSFOREIGNKEYS_DELETERULE, new SQLChar(raDeleteRule));
    /* 5th column is UPDATERULE char(1) */
    row.setColumn(SYSFOREIGNKEYS_UPDATERULE, new SQLChar(raUpdateRule));
    return row;
}
Also used : ReferencedKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor) SQLChar(org.apache.derby.iapi.types.SQLChar) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor) ExecIndexRow(org.apache.derby.iapi.sql.execute.ExecIndexRow) ForeignKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor)

Example 10 with ReferencedKeyConstraintDescriptor

use of org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor in project derby by apache.

the class DMLModStatementNode method generateFKInfo.

/**
 * Generate the FKInfo structures used during code generation.
 * For each constraint that isn't a check constraint, add another
 * one of these FKInfo structures and then package them up into
 * a single array.
 *
 * @param cdl				The constraint descriptor list
 * @param dd				The DataDictionary
 * @param td				The TableDescriptor
 * @param readColsBitSet 	columns read
 *
 * @exception StandardException		Thrown on failure
 */
private void generateFKInfo(ConstraintDescriptorList cdl, DataDictionary dd, TableDescriptor td, FormatableBitSet readColsBitSet) throws StandardException {
    ArrayList<FKInfo> fkList = new ArrayList<FKInfo>();
    int type;
    UUID[] uuids;
    long[] conglomNumbers;
    String[] fkNames;
    ConstraintDescriptorList fkcdl;
    ReferencedKeyConstraintDescriptor refcd;
    boolean[] isSelfReferencingFK;
    ConstraintDescriptorList activeList = dd.getActiveConstraintDescriptors(cdl);
    int[] rowMap = getRowMap(readColsBitSet, td);
    int[] raRules;
    boolean[] deferrable;
    UUID[] fkIds;
    ArrayList<String> refSchemaNames = new ArrayList<String>(1);
    ArrayList<String> refTableNames = new ArrayList<String>(1);
    ArrayList<Long> refIndexConglomNum = new ArrayList<Long>(1);
    ArrayList<Integer> refActions = new ArrayList<Integer>(1);
    ArrayList<ColumnDescriptorList> refColDescriptors = new ArrayList<ColumnDescriptorList>(1);
    ArrayList<int[]> fkColMap = new ArrayList<int[]>(1);
    int activeSize = activeList.size();
    for (int index = 0; index < activeSize; index++) {
        ConstraintDescriptor cd = activeList.elementAt(index);
        if (cd instanceof ForeignKeyConstraintDescriptor) {
            /*
				** We are saving information for checking the
				** primary/unique key that is referenced by this
				** foreign key, so type is FOREIGN KEY.
				*/
            type = FKInfo.FOREIGN_KEY;
            refcd = ((ForeignKeyConstraintDescriptor) cd).getReferencedConstraint();
            uuids = new UUID[1];
            deferrable = new boolean[1];
            fkIds = new UUID[1];
            conglomNumbers = new long[1];
            fkNames = new String[1];
            isSelfReferencingFK = new boolean[1];
            raRules = new int[1];
            fkSetupArrays(dd, (ForeignKeyConstraintDescriptor) cd, 0, uuids, conglomNumbers, fkNames, isSelfReferencingFK, raRules, deferrable, fkIds);
            // oops, get the right constraint name -- for error
            // handling we want the FK name, not refcd name
            fkNames[0] = cd.getConstraintName();
        } else if (cd instanceof ReferencedKeyConstraintDescriptor) {
            refcd = (ReferencedKeyConstraintDescriptor) cd;
            /*
				** We are saving information for checking the
				** foreign key(s) that is dependent on this referenced
				** key, so type is REFERENCED KEY.
				*/
            type = FKInfo.REFERENCED_KEY;
            fkcdl = dd.getActiveConstraintDescriptors(((ReferencedKeyConstraintDescriptor) cd).getForeignKeyConstraints(ConstraintDescriptor.ENABLED));
            int size = fkcdl.size();
            if (size == 0) {
                continue;
            }
            uuids = new UUID[size];
            deferrable = new boolean[size];
            fkIds = new UUID[size];
            fkNames = new String[size];
            conglomNumbers = new long[size];
            isSelfReferencingFK = new boolean[size];
            raRules = new int[size];
            TableDescriptor fktd;
            ColumnDescriptorList coldl;
            int[] refColumns;
            ColumnDescriptor cold;
            int[] colArray = remapReferencedColumns(cd, rowMap);
            for (int inner = 0; inner < size; inner++) {
                ForeignKeyConstraintDescriptor fkcd = (ForeignKeyConstraintDescriptor) fkcdl.elementAt(inner);
                fkSetupArrays(dd, fkcd, inner, uuids, conglomNumbers, fkNames, isSelfReferencingFK, raRules, deferrable, fkIds);
                if ((raRules[inner] == StatementType.RA_CASCADE) || (raRules[inner] == StatementType.RA_SETNULL)) {
                    // find  the referencing  table Name
                    fktd = fkcd.getTableDescriptor();
                    refSchemaNames.add(fktd.getSchemaName());
                    refTableNames.add(fktd.getName());
                    refActions.add(Integer.valueOf(raRules[inner]));
                    // find the referencing column name required for update null.
                    refColumns = fkcd.getReferencedColumns();
                    coldl = fktd.getColumnDescriptorList();
                    ColumnDescriptorList releventColDes = new ColumnDescriptorList();
                    for (int i = 0; i < refColumns.length; i++) {
                        cold = coldl.elementAt(refColumns[i] - 1);
                        releventColDes.add(cold);
                    }
                    refColDescriptors.add(releventColDes);
                    refIndexConglomNum.add(Long.valueOf(conglomNumbers[inner]));
                    fkColMap.add(colArray);
                }
            }
        } else {
            continue;
        }
        final TableDescriptor pktd = refcd.getTableDescriptor();
        final UUID pkIndexId = refcd.getIndexId();
        final ConglomerateDescriptor pkIndexConglom = pktd.getConglomerateDescriptor(pkIndexId);
        final TableDescriptor refTd = cd.getTableDescriptor();
        fkList.add(new FKInfo(// foreign key names
        fkNames, cd.getSchemaDescriptor().getSchemaName(), // table being modified
        refTd.getName(), // INSERT|UPDATE|DELETE
        statementType, // FOREIGN_KEY|REFERENCED_KEY
        type, // referenced backing index uuid
        pkIndexId, pkIndexConglom.getConglomerateNumber(), // referenced backing index conglom
        refcd.getUUID(), // referenced constraint is
        refcd.deferrable(), // fk backing index uuids
        uuids, // fk backing index congloms
        conglomNumbers, // is self ref array of bool
        isSelfReferencingFK, remapReferencedColumns(cd, rowMap), // columns referenced by key
        dd.getRowLocationTemplate(getLanguageConnectionContext(), refTd), // referential action rules
        raRules, // deferrable flags
        deferrable, // UUID of fks
        fkIds));
    }
    // Now convert the list into an array.
    if (!fkList.isEmpty()) {
        fkInfo = fkList.toArray(new FKInfo[fkList.size()]);
    }
    // Convert the ref action info lists to arrays.
    int size = refActions.size();
    if (size > 0) {
        fkTableNames = new String[size];
        fkSchemaNames = new String[size];
        fkRefActions = new int[size];
        fkColDescriptors = new ColumnDescriptorList[size];
        fkIndexConglomNumbers = new long[size];
        fkColArrays = new int[size][];
        for (int i = 0; i < size; i++) {
            fkTableNames[i] = refTableNames.get(i);
            fkSchemaNames[i] = refSchemaNames.get(i);
            fkRefActions[i] = (refActions.get(i)).intValue();
            fkColDescriptors[i] = refColDescriptors.get(i);
            fkIndexConglomNumbers[i] = (refIndexConglomNum.get(i)).longValue();
            fkColArrays[i] = (fkColMap.get(i));
        }
    }
}
Also used : ArrayList(java.util.ArrayList) ColumnDescriptorList(org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList) UUID(org.apache.derby.catalog.UUID) FKInfo(org.apache.derby.impl.sql.execute.FKInfo) ColumnDescriptor(org.apache.derby.iapi.sql.dictionary.ColumnDescriptor) ConstraintDescriptorList(org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList) ForeignKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor) ConglomerateDescriptor(org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor) TableDescriptor(org.apache.derby.iapi.sql.dictionary.TableDescriptor) ReferencedKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor) ForeignKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor) ConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor) ReferencedKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor)

Aggregations

ReferencedKeyConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor)12 ConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor)9 ForeignKeyConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor)9 ConstraintDescriptorList (org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList)7 LanguageConnectionContext (org.apache.derby.iapi.sql.conn.LanguageConnectionContext)5 DependencyManager (org.apache.derby.iapi.sql.depend.DependencyManager)5 DataDictionary (org.apache.derby.iapi.sql.dictionary.DataDictionary)5 TransactionController (org.apache.derby.iapi.store.access.TransactionController)5 UUID (org.apache.derby.catalog.UUID)4 ColumnDescriptor (org.apache.derby.iapi.sql.dictionary.ColumnDescriptor)3 ConglomerateDescriptor (org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor)3 TableDescriptor (org.apache.derby.iapi.sql.dictionary.TableDescriptor)3 ArrayList (java.util.ArrayList)2 ReferencedColumnsDescriptorImpl (org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl)2 FormatableBitSet (org.apache.derby.iapi.services.io.FormatableBitSet)2 CheckConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor)2 ColumnDescriptorList (org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList)2 DataDescriptorGenerator (org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator)2 SchemaDescriptor (org.apache.derby.iapi.sql.dictionary.SchemaDescriptor)2 TriggerDescriptor (org.apache.derby.iapi.sql.dictionary.TriggerDescriptor)2