Search in sources :

Example 1 with ConstantAction

use of org.apache.derby.iapi.sql.execute.ConstantAction 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 2 with ConstantAction

use of org.apache.derby.iapi.sql.execute.ConstantAction in project derby by apache.

the class AlterTableConstantAction method getAffectedIndexes.

/**
 * Get info on the indexes on the table being compressed.
 *
 * @exception StandardException		Thrown on error
 */
private void getAffectedIndexes() throws StandardException {
    IndexLister indexLister = td.getIndexLister();
    /* We have to get non-distinct index row generaters and conglom numbers
		 * here and then compress it to distinct later because drop column
		 * will need to change the index descriptor directly on each index
		 * entry in SYSCONGLOMERATES, on duplicate indexes too.
		 */
    compressIRGs = indexLister.getIndexRowGenerators();
    numIndexes = compressIRGs.length;
    indexConglomerateNumbers = indexLister.getIndexConglomerateNumbers();
    if (// then it's drop column
    !(compressTable || truncateTable)) {
        ArrayList<ConstantAction> newCongloms = new ArrayList<ConstantAction>();
        for (int i = 0; i < compressIRGs.length; i++) {
            int[] baseColumnPositions = compressIRGs[i].baseColumnPositions();
            int j;
            for (j = 0; j < baseColumnPositions.length; j++) if (baseColumnPositions[j] == droppedColumnPosition)
                break;
            if (// not related
            j == baseColumnPositions.length)
                continue;
            if (baseColumnPositions.length == 1 || (behavior == StatementType.DROP_CASCADE && compressIRGs[i].isUnique())) {
                numIndexes--;
                /* get first conglomerate with this conglom number each time
					 * and each duplicate one will be eventually all dropped
					 */
                ConglomerateDescriptor cd = td.getConglomerateDescriptor(indexConglomerateNumbers[i]);
                dropConglomerate(cd, td, true, newCongloms, activation, activation.getLanguageConnectionContext());
                // mark it
                compressIRGs[i] = null;
                continue;
            }
            // a constraint, because constraints have already been handled
            if (compressIRGs[i].isUnique()) {
                ConglomerateDescriptor cd = td.getConglomerateDescriptor(indexConglomerateNumbers[i]);
                throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, dm.getActionString(DependencyManager.DROP_COLUMN), columnInfo[0].name, "UNIQUE INDEX", cd.getConglomerateName());
            }
        }
        /* 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 conglomerate" call above), then create
			 * them now.  We do this *after* dropping all dependent
			 * conglomerates 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 conglomerate"
			 * call.
			 */
        createNewBackingCongloms(newCongloms, indexConglomerateNumbers);
        IndexRowGenerator[] newIRGs = new IndexRowGenerator[numIndexes];
        long[] newIndexConglomNumbers = new long[numIndexes];
        collation = new int[numIndexes][];
        for (int i = 0, j = 0; i < numIndexes; i++, j++) {
            while (compressIRGs[j] == null) j++;
            // Setup collation id array to be passed in on call to create index.
            collation[i] = compressIRGs[j].getColumnCollationIds(td.getColumnDescriptorList());
            int[] baseColumnPositions = compressIRGs[j].baseColumnPositions();
            newIRGs[i] = compressIRGs[j];
            newIndexConglomNumbers[i] = indexConglomerateNumbers[j];
            boolean[] isAscending = compressIRGs[j].isAscending();
            boolean reMakeArrays = false;
            boolean rewriteBaseColumnPositions = false;
            int size = baseColumnPositions.length;
            for (int k = 0; k < size; k++) {
                if (baseColumnPositions[k] > droppedColumnPosition) {
                    baseColumnPositions[k]--;
                    rewriteBaseColumnPositions = true;
                } else if (baseColumnPositions[k] == droppedColumnPosition) {
                    // mark it
                    baseColumnPositions[k] = 0;
                    reMakeArrays = true;
                }
            }
            if (rewriteBaseColumnPositions) {
                compressIRGs[j].setBaseColumnPositions(baseColumnPositions);
            }
            if (reMakeArrays) {
                size--;
                int[] newBCP = new int[size];
                boolean[] newIsAscending = new boolean[size];
                int[] newCollation = new int[collation[i].length - 1];
                for (int k = 0, step = 0; k < size; k++) {
                    if (step == 0 && baseColumnPositions[k + step] == 0)
                        step++;
                    newBCP[k] = baseColumnPositions[k + step];
                    newIsAscending[k] = isAscending[k + step];
                    newCollation[k] = collation[i][k + step];
                }
                IndexDescriptor id = compressIRGs[j].getIndexDescriptor();
                id.setBaseColumnPositions(newBCP);
                id.setIsAscending(newIsAscending);
                id.setNumberOfOrderedColumns(id.numberOfOrderedColumns() - 1);
                collation[i] = newCollation;
            }
        }
        compressIRGs = newIRGs;
        indexConglomerateNumbers = newIndexConglomNumbers;
    } else {
        collation = new int[numIndexes][];
        for (int i = 0; i < numIndexes; i++) {
            collation[i] = compressIRGs[i].getColumnCollationIds(td.getColumnDescriptorList());
        }
    }
    /* Now we are done with updating each index descriptor entry directly
		 * in SYSCONGLOMERATES (for duplicate index as well), from now on, our
		 * work should apply ONLY once for each real conglomerate, so we
		 * compress any duplicate indexes now.
		 */
    Object[] compressIndexResult = compressIndexArrays(indexConglomerateNumbers, compressIRGs);
    if (compressIndexResult != null) {
        indexConglomerateNumbers = (long[]) compressIndexResult[1];
        compressIRGs = (IndexRowGenerator[]) compressIndexResult[2];
        numIndexes = indexConglomerateNumbers.length;
    }
    indexedCols = new FormatableBitSet(compressTable || truncateTable ? td.getNumberOfColumns() + 1 : td.getNumberOfColumns());
    for (int index = 0; index < numIndexes; index++) {
        int[] colIds = compressIRGs[index].getIndexDescriptor().baseColumnPositions();
        for (int index2 = 0; index2 < colIds.length; index2++) {
            indexedCols.set(colIds[index2]);
        }
    }
}
Also used : ArrayList(java.util.ArrayList) IndexLister(org.apache.derby.iapi.sql.dictionary.IndexLister) IndexDescriptor(org.apache.derby.catalog.IndexDescriptor) ConglomerateDescriptor(org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor) ConstantAction(org.apache.derby.iapi.sql.execute.ConstantAction) IndexRowGenerator(org.apache.derby.iapi.sql.dictionary.IndexRowGenerator) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet)

Example 3 with ConstantAction

use of org.apache.derby.iapi.sql.execute.ConstantAction in project derby by apache.

the class DDLSingleTableConstantAction method recreateUniqueConstraintBackingIndexAsUniqueWhenNotNull.

/**
 * Recreate backing index of unique constraint.
 *
 * It first drops the existing index and creates it again with
 * uniqueness set to false and uniqueWhenNotNull set to true. It reuses
 * the uuid so there is no need to update ConstraintDescriptor.
 *
 * @param cd            ConglomerateDescritor to recreate
 * @param td            TableDescriptor for table on which congDesc exists
 * @param activation    Activation used when creating a new backing index
 *                      (if a new backing index is needed)
 * @param lcc           LanguageConnectionContext used for dropping
 *
 * @throws StandardException
 */
void recreateUniqueConstraintBackingIndexAsUniqueWhenNotNull(ConglomerateDescriptor cd, TableDescriptor td, Activation activation, LanguageConnectionContext lcc) throws StandardException {
    // get index property
    Properties prop = new Properties();
    loadIndexProperties(lcc, cd, prop);
    ArrayList<ConstantAction> list = new ArrayList<ConstantAction>();
    // drop the existing index.
    dropConglomerate(cd, td, false, list, activation, lcc);
    String[] cols = cd.getColumnNames();
    if (cols == null) {
        // column list wasn't stored in conglomerateDescriptor
        // fetch is from table descriptor
        int[] pos = cd.getIndexDescriptor().baseColumnPositions();
        cols = new String[pos.length];
        for (int i = 0; i < cols.length; i++) {
            cols[i] = td.getColumnDescriptor(pos[i]).getColumnName();
        }
    }
    // create new index action
    CreateIndexConstantAction action = new CreateIndexConstantAction(// not part of create table
    false, // not unique
    false, // create as unique when not null index
    true, cd.getIndexDescriptor().hasDeferrableChecking(), // deferred or not: shouldn't matter
    false, // unique index
    DataDictionary.UNIQUE_CONSTRAINT, cd.getIndexDescriptor().indexType(), td.getSchemaName(), cd.getConglomerateName(), td.getName(), td.getUUID(), cols, cd.getIndexDescriptor().isAscending(), true, cd.getUUID(), prop);
    // create index
    action.executeConstantAction(activation);
}
Also used : ConstantAction(org.apache.derby.iapi.sql.execute.ConstantAction) ArrayList(java.util.ArrayList) Properties(java.util.Properties)

Aggregations

ArrayList (java.util.ArrayList)3 ConstantAction (org.apache.derby.iapi.sql.execute.ConstantAction)3 FormatableBitSet (org.apache.derby.iapi.services.io.FormatableBitSet)2 Properties (java.util.Properties)1 DependableFinder (org.apache.derby.catalog.DependableFinder)1 IndexDescriptor (org.apache.derby.catalog.IndexDescriptor)1 UUID (org.apache.derby.catalog.UUID)1 ReferencedColumnsDescriptorImpl (org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl)1 CheckConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor)1 ColumnDescriptor (org.apache.derby.iapi.sql.dictionary.ColumnDescriptor)1 ColumnDescriptorList (org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList)1 ConglomerateDescriptor (org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor)1 ConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor)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 ForeignKeyConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor)1 IndexLister (org.apache.derby.iapi.sql.dictionary.IndexLister)1 IndexRowGenerator (org.apache.derby.iapi.sql.dictionary.IndexRowGenerator)1 ReferencedKeyConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor)1