Search in sources :

Example 6 with TriggerDescriptor

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

the class SYSTRIGGERSRowFactory method buildDescriptor.

// /////////////////////////////////////////////////////////////////////////
// 
// ABSTRACT METHODS TO BE IMPLEMENTED BY CHILDREN OF CatalogRowFactory
// 
// /////////////////////////////////////////////////////////////////////////
/**
 * Make an  Tuple Descriptor out of a SYSTRIGGERS row
 *
 * @param row 					a SYSTRIGGERS row
 * @param parentTupleDescriptor	unused
 * @param dd 					dataDictionary
 *
 * @return	a  descriptor equivalent to a SYSTRIGGERS row
 *
 * @exception   StandardException thrown on failure
 */
public TupleDescriptor buildDescriptor(ExecRow row, TupleDescriptor parentTupleDescriptor, DataDictionary dd) throws StandardException {
    DataValueDescriptor col;
    String name;
    char theChar;
    String uuidStr;
    String triggerDefinition;
    String oldReferencingName;
    String newReferencingName;
    UUID uuid;
    // schema
    UUID suuid;
    // referenced table
    UUID tuuid;
    // action sps uuid string
    UUID actionSPSID = null;
    // when clause sps uuid string
    UUID whenSPSID = null;
    Timestamp createTime;
    int eventMask = 0;
    boolean isBefore;
    boolean isRow;
    boolean isEnabled;
    boolean referencingOld;
    boolean referencingNew;
    ReferencedColumns rcd;
    TriggerDescriptor descriptor;
    DataDescriptorGenerator ddg = dd.getDataDescriptorGenerator();
    if (SanityManager.DEBUG) {
        // The expected number of columns depends on the version of the
        // data dictionary. The WHENCLAUSETEXT column was added in version
        // 10.11 (DERBY-534).
        int expectedCols = dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_11, null) ? SYSTRIGGERS_COLUMN_COUNT : (SYSTRIGGERS_COLUMN_COUNT - 1);
        SanityManager.ASSERT(row.nColumns() == expectedCols, "Wrong number of columns for a SYSTRIGGERS row");
    }
    // 1st column is TRIGGERID (UUID - char(36))
    col = row.getColumn(1);
    uuidStr = col.getString();
    uuid = getUUIDFactory().recreateUUID(uuidStr);
    // 2nd column is TRIGGERNAME (varchar(128))
    col = row.getColumn(2);
    name = col.getString();
    // 3rd column is SCHEMAID (UUID - char(36))
    col = row.getColumn(3);
    uuidStr = col.getString();
    suuid = getUUIDFactory().recreateUUID(uuidStr);
    // 4th column is CREATIONTIMESTAMP (TIMESTAMP)
    col = row.getColumn(4);
    createTime = col.getTimestamp(getCalendarForCreationTimestamp());
    // 5th column is EVENT (char(1))
    col = row.getColumn(5);
    theChar = col.getString().charAt(0);
    switch(theChar) {
        case 'U':
            eventMask = TriggerDescriptor.TRIGGER_EVENT_UPDATE;
            break;
        case 'I':
            eventMask = TriggerDescriptor.TRIGGER_EVENT_INSERT;
            break;
        case 'D':
            eventMask = TriggerDescriptor.TRIGGER_EVENT_DELETE;
            break;
        default:
            if (SanityManager.DEBUG) {
                SanityManager.THROWASSERT("bad event mask: " + theChar);
            }
    }
    // 6th column is FIRINGTIME (char(1))
    isBefore = getCharBoolean(row.getColumn(6), 'B', 'A');
    // 7th column is TYPE (char(1))
    isRow = getCharBoolean(row.getColumn(7), 'R', 'S');
    // 8th column is STATE (char(1))
    isEnabled = getCharBoolean(row.getColumn(8), 'E', 'D');
    // 9th column is TABLEID (UUID - char(36))
    col = row.getColumn(9);
    uuidStr = col.getString();
    tuuid = getUUIDFactory().recreateUUID(uuidStr);
    // 10th column is WHENSTMTID (UUID - char(36))
    col = row.getColumn(10);
    uuidStr = col.getString();
    if (uuidStr != null)
        whenSPSID = getUUIDFactory().recreateUUID(uuidStr);
    // 11th column is ACTIONSTMTID (UUID - char(36))
    col = row.getColumn(11);
    uuidStr = col.getString();
    if (uuidStr != null)
        actionSPSID = getUUIDFactory().recreateUUID(uuidStr);
    // 12th column is REFERENCEDCOLUMNS user type org.apache.derby.catalog.ReferencedColumns
    col = row.getColumn(12);
    rcd = (ReferencedColumns) col.getObject();
    // 13th column is TRIGGERDEFINITION (longvarchar)
    col = row.getColumn(13);
    triggerDefinition = col.getString();
    // 14th column is REFERENCINGOLD (boolean)
    col = row.getColumn(14);
    referencingOld = col.getBoolean();
    // 15th column is REFERENCINGNEW (boolean)
    col = row.getColumn(15);
    referencingNew = col.getBoolean();
    // 16th column is REFERENCINGNAME (varchar(128))
    col = row.getColumn(16);
    oldReferencingName = col.getString();
    // 17th column is REFERENCINGNAME (varchar(128))
    col = row.getColumn(17);
    newReferencingName = col.getString();
    // 18th column is WHENCLAUSETEXT (longvarchar)
    String whenClauseText = null;
    if (row.nColumns() >= 18) {
        // This column is present only if the data dictionary version is
        // 10.11 or higher.
        col = row.getColumn(18);
        whenClauseText = col.getString();
    }
    descriptor = ddg.newTriggerDescriptor(dd.getSchemaDescriptor(suuid, null), uuid, name, eventMask, isBefore, isRow, isEnabled, dd.getTableDescriptor(tuuid), whenSPSID, actionSPSID, createTime, (rcd == null) ? (int[]) null : rcd.getReferencedColumnPositions(), (rcd == null) ? (int[]) null : rcd.getTriggerActionReferencedColumnPositions(), triggerDefinition, referencingOld, referencingNew, oldReferencingName, newReferencingName, whenClauseText);
    return descriptor;
}
Also used : DataDescriptorGenerator(org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator) ReferencedColumns(org.apache.derby.catalog.ReferencedColumns) SQLVarchar(org.apache.derby.iapi.types.SQLVarchar) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor) UUID(org.apache.derby.catalog.UUID) SQLTimestamp(org.apache.derby.iapi.types.SQLTimestamp) Timestamp(java.sql.Timestamp) TriggerDescriptor(org.apache.derby.iapi.sql.dictionary.TriggerDescriptor)

Example 7 with TriggerDescriptor

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

the class DeleteNode method getDeleteReadMap.

/**
 *	Builds a bitmap of all columns which should be read from the
 *	Store in order to satisfy an DELETE statement.
 *
 *	1)	finds all indices on this table
 *	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 DELETE triggers on the table
 *	5)	if there are any DELETE triggers, then do one of the following
 *     a)If all of the triggers have MISSING referencing clause, then that
 *      means that the trigger actions do not have access to before and
 *      after values. In that case, there is no need to blanketly decide
 *      to include all the columns in the read map just because there are
 *      triggers defined on the table.
 *     b)Since one/more triggers have REFERENCING clause on them, get all
 *      the columns because we don't know what the user will ultimately
 *      reference.
 *	6)	adds the triggers to an evolving list of triggers
 *
 * @param  conglomerates       OUT: list of affected indices
 *	@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 requires
 *											deferred processing
 *
 * @return a FormatableBitSet of columns to be read out of the base table
 *
 * @exception StandardException		Thrown on error
 */
private static FormatableBitSet getDeleteReadMap(TableDescriptor baseTable, List<ConglomerateDescriptor> conglomerates, TriggerDescriptorList relevantTriggers, boolean[] needsDeferredProcessing) throws StandardException {
    int columnCount = baseTable.getMaxColumnID();
    FormatableBitSet columnMap = new FormatableBitSet(columnCount + 1);
    /* 
		** 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.
		**
		** Notice that we don't need to add constraint
		** columns.  This is because we add all key constraints
		** (e.g. foreign keys) as a side effect of adding their
		** indexes above.  And we don't need to deal with
		** check constraints on a delete.
		**
		** Adding indexes also takes care of the replication 
		** requirement of having the primary key.
		*/
    DMLModStatementNode.getXAffectedIndexes(baseTable, null, columnMap, conglomerates);
    /*
	 	** If we have any DELETE triggers, then do one of the following
	 	** 1)If all of the triggers have MISSING referencing clause, then that
	 	** means that the trigger actions do not have access to before and 
	 	** after values. In that case, there is no need to blanketly decide to
	 	** include all the columns in the read map just because there are
	 	** triggers defined on the table.
	 	** 2)Since one/more triggers have REFERENCING clause on them, get all 
	 	** the columns because we don't know what the user will ultimately reference.
	 	*/
    baseTable.getAllRelevantTriggers(StatementType.DELETE, (int[]) null, relevantTriggers);
    if (relevantTriggers.size() > 0) {
        needsDeferredProcessing[0] = true;
        boolean needToIncludeAllColumns = false;
        for (TriggerDescriptor trd : relevantTriggers) {
            // If yes, then read all the columns from the trigger table.
            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 : FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet) TriggerDescriptor(org.apache.derby.iapi.sql.dictionary.TriggerDescriptor)

Example 8 with TriggerDescriptor

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

the class DropTriggerConstantAction method executeConstantAction.

/**
 *	This is the guts of the Execution-time logic for DROP STATEMENT.
 *
 *	@see ConstantAction#executeConstantAction
 *
 * @exception StandardException		Thrown on failure
 */
public void executeConstantAction(Activation activation) throws StandardException {
    TriggerDescriptor triggerd;
    LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
    DataDictionary dd = lcc.getDataDictionary();
    /*
		** 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);
    TableDescriptor td = dd.getTableDescriptor(tableId);
    if (td == null) {
        throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION, tableId.toString());
    }
    TransactionController tc = lcc.getTransactionExecute();
    lockTableForDDL(tc, td.getHeapConglomerateId(), true);
    // get td again in case table shape is changed before lock is acquired
    td = dd.getTableDescriptor(tableId);
    if (td == null) {
        throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION, tableId.toString());
    }
    /* 
		** Get the trigger descriptor.  We're responsible for raising
		** the error if it isn't found 
		*/
    triggerd = dd.getTriggerDescriptor(triggerName, sd);
    if (triggerd == null) {
        throw StandardException.newException(SQLState.LANG_OBJECT_NOT_FOUND_DURING_EXECUTION, "TRIGGER", (sd.getSchemaName() + "." + triggerName));
    }
    /* 
	 	** Prepare all dependents to invalidate.  (This is there chance
		** to say that they can't be invalidated.  For example, an open
		** cursor referencing a table/trigger that the user is attempting to
		** drop.) If no one objects, then invalidate any dependent objects.
		*/
    triggerd.drop(lcc);
}
Also used : LanguageConnectionContext(org.apache.derby.iapi.sql.conn.LanguageConnectionContext) DataDictionary(org.apache.derby.iapi.sql.dictionary.DataDictionary) TransactionController(org.apache.derby.iapi.store.access.TransactionController) TableDescriptor(org.apache.derby.iapi.sql.dictionary.TableDescriptor) TriggerDescriptor(org.apache.derby.iapi.sql.dictionary.TriggerDescriptor)

Example 9 with TriggerDescriptor

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

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

Aggregations

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