Search in sources :

Example 11 with TriggerDescriptor

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

the class UpdateNode method getUpdateReadMap.

/**
 *	Builds a bitmap of all columns which should be read from the
 *	Store in order to satisfy an UPDATE statement.
 *
 *	Is passed a list of updated columns. Does the following:
 *
 *	1)	finds all indices which overlap the updated columns
 *	2)	adds the index columns to a bitmap of affected columns
 *	3)	adds the index descriptors to a list of conglomerate
 *		descriptors.
 *	4)	finds all constraints which overlap the updated columns
 *		and adds the constrained columns to the bitmap
 *	5)	finds all triggers which overlap the updated columns.
 *	6)	Go through all those triggers from step 5 and for each one of
 *     those triggers, follow the rules below to decide which columns
 *     should be read.
 *       Rule1)If trigger column information is null, then read all the
 *       columns from trigger table into memory irrespective of whether
 *       there is any trigger action column information. 2 egs of such
 *       triggers
 *         create trigger tr1 after update on t1 for each row values(1);
 *         create trigger tr1 after update on t1 referencing old as oldt
 *         	for each row insert into t2 values(2,oldt.j,-2);
 *       Rule2)If trigger column information is available but no trigger
 *       action column information is found and no REFERENCES clause is
 *       used for the trigger, then read all the columns identified by
 *       the trigger column. eg
 *         create trigger tr1 after update of c1 on t1
 *         	for each row values(1);
 *       Rule3)If trigger column information and trigger action column
 *       information both are not null, then only those columns will be
 *       read into memory. This is possible only for triggers created in
 *       release 10.9 or higher(with the exception of 10.7.1.1 where we
 *       did collect that information but because of corruption caused
 *       by those changes, we do not use the information collected by
 *       10.7). Starting 10.9, we are collecting trigger action column
 *       informatoin so we can be smart about what columns get read
 *       during trigger execution. eg
 *         create trigger tr1 after update of c1 on t1
 *         	referencing old as oldt for each row
 *         	insert into t2 values(2,oldt.j,-2);
 *       Rule4)If trigger column information is available but no trigger
 *       action column information is found but REFERENCES clause is used
 *       for the trigger, then read all the columns from the trigger
 *       table. This will cover soft-upgrade scenario for triggers created
 *       pre-10.9.
 *       eg trigger created prior to 10.9
 *         create trigger tr1 after update of c1 on t1
 *         	referencing old as oldt for each row
 *         	insert into t2 values(2,oldt.j,-2);
 *	7)	adds the triggers to an evolving list of triggers
 *	8)	finds all generated columns whose generation clauses mention
 *        the updated columns and adds all of the mentioned columns
 *
 *	@param	dd	Data Dictionary
 *	@param	baseTable	Table on which update is issued
 *	@param	updateColumnList	a list of updated columns
 * @param  conglomerates       OUT: list of affected indices
 *	@param	relevantConstraints	IN/OUT. Empty list is passed in. We hang constraints on it as we go.
 *	@param	relevantTriggers	IN/OUT. Passed in as an empty list. Filled in as we go.
 *	@param	needsDeferredProcessing	IN/OUT. true if the statement already needs
 *									deferred processing. set while evaluating this
 *									routine if a trigger or constraint requires
 *									deferred processing
 *	@param	affectedGeneratedColumns columns whose generation clauses mention updated columns
 *
 * @return a FormatableBitSet of columns to be read out of the base table
 *
 * @exception StandardException		Thrown on error
 */
static FormatableBitSet getUpdateReadMap(DataDictionary dd, TableDescriptor baseTable, ResultColumnList updateColumnList, List<ConglomerateDescriptor> conglomerates, ConstraintDescriptorList relevantConstraints, TriggerDescriptorList relevantTriggers, boolean[] needsDeferredProcessing, ColumnDescriptorList affectedGeneratedColumns) throws StandardException {
    if (SanityManager.DEBUG) {
        SanityManager.ASSERT(updateColumnList != null, "updateColumnList is null");
    }
    int columnCount = baseTable.getMaxColumnID();
    FormatableBitSet columnMap = new FormatableBitSet(columnCount + 1);
    /*
		** Add all the changed columns.  We don't strictly
		** need the before image of the changed column in all cases,
		** but it makes life much easier since things are set
		** up around the assumption that we have the before
		** and after image of the column.
		*/
    int[] changedColumnIds = updateColumnList.sortMe();
    for (int ix = 0; ix < changedColumnIds.length; ix++) {
        columnMap.set(changedColumnIds[ix]);
    }
    /* 
		** Get a list of the indexes that need to be 
		** updated.  ColumnMap contains all indexed
		** columns where 1 or more columns in the index
		** are going to be modified.
		*/
    DMLModStatementNode.getXAffectedIndexes(baseTable, updateColumnList, columnMap, conglomerates);
    /* 
		** Add all columns needed for constraints.  We don't
		** need to bother with foreign key/primary key constraints
		** because they are added as a side effect of adding
		** their indexes above.
		*/
    baseTable.getAllRelevantConstraints(StatementType.UPDATE, changedColumnIds, needsDeferredProcessing, relevantConstraints);
    int rclSize = relevantConstraints.size();
    for (int index = 0; index < rclSize; index++) {
        ConstraintDescriptor cd = relevantConstraints.elementAt(index);
        if (cd.getConstraintType() != DataDictionary.CHECK_CONSTRAINT) {
            continue;
        }
        int[] refColumns = ((CheckConstraintDescriptor) cd).getReferencedColumns();
        for (int i = 0; i < refColumns.length; i++) {
            columnMap.set(refColumns[i]);
        }
    }
    // 
    // Add all columns mentioned by generation clauses which are affected
    // by the columns being updated.
    // 
    addGeneratedColumnPrecursors(baseTable, affectedGeneratedColumns, columnMap);
    /*
	 	* If we have any UPDATE triggers, then we will follow the 4 rules
	 	* mentioned in the comments at the method level.
	 	*/
    baseTable.getAllRelevantTriggers(StatementType.UPDATE, changedColumnIds, relevantTriggers);
    if (relevantTriggers.size() > 0) {
        needsDeferredProcessing[0] = true;
        boolean needToIncludeAllColumns = false;
        // If we are dealing with database created in 10.8 and prior,
        // then we must be in soft upgrade mode. For such databases,
        // we do not want to do any column reading optimization.
        // 
        // For triggers created in 10.7.1.1, we kept track of trigger
        // action columns used through the REFERENCING clause. That
        // information was gathered so we could be smart about what
        // columns from trigger table should be read during trigger
        // execution. But those changes in code resulted in data
        // corruption DERBY-5121. Because of that, we took out the
        // column read optimization changes from codeline for next
        // release of 10.7 and 10.8 codeline.
        // But we can still have triggers created in 10.7.1.1 with
        // trigger action column information in SYSTRIGGERS.
        // In 10.9, we are reimplementing what columns should be read
        // from the trigger table during trigger execution. But we do
        // not want this column optimization changes to be used in soft
        // upgrade mode for a 10.8 or prior database so that we can
        // go back to the older release if that's what the user chooses
        // after the soft-upgrade.
        boolean in10_9_orHigherVersion = dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_9, null);
        for (TriggerDescriptor trd : relevantTriggers) {
            if (in10_9_orHigherVersion) {
                // See if we can avoid reading all the columns from the
                // trigger table.
                int[] referencedColsInTriggerAction = trd.getReferencedColsInTriggerAction();
                int[] triggerCols = trd.getReferencedCols();
                if (triggerCols == null || triggerCols.length == 0) {
                    for (int i = 0; i < columnCount; i++) {
                        columnMap.set(i + 1);
                    }
                    // going to read all the columns anyways.
                    break;
                } else {
                    if (referencedColsInTriggerAction == null || referencedColsInTriggerAction.length == 0) {
                        // Does this trigger have REFERENCING clause defined on it
                        if (!trd.getReferencingNew() && !trd.getReferencingOld()) {
                            // trigger columns
                            for (int ix = 0; ix < triggerCols.length; ix++) {
                                columnMap.set(triggerCols[ix]);
                            }
                        } else {
                            // The trigger has REFERENCING clause defined on it
                            // so it might be used them in trigger action.
                            // We should just go ahead and read all the
                            // columns from the trigger table. Now, there is
                            // no need to go through the rest of the triggers
                            // because we are going to read all the columns
                            // anyways.
                            needToIncludeAllColumns = true;
                            break;
                        }
                    } else {
                        // trigger table for the trigger execution.
                        for (int ix = 0; ix < triggerCols.length; ix++) {
                            columnMap.set(triggerCols[ix]);
                        }
                        for (int ix = 0; ix < referencedColsInTriggerAction.length; ix++) {
                            columnMap.set(referencedColsInTriggerAction[ix]);
                        }
                    }
                }
            } else {
                // Does this trigger have REFERENCING clause defined on it
                if (!trd.getReferencingNew() && !trd.getReferencingOld())
                    continue;
                else {
                    needToIncludeAllColumns = true;
                    break;
                }
            }
        }
        if (needToIncludeAllColumns) {
            for (int i = 1; i <= columnCount; i++) {
                columnMap.set(i);
            }
        }
    }
    return columnMap;
}
Also used : CheckConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor) ConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet) CheckConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor) TriggerDescriptor(org.apache.derby.iapi.sql.dictionary.TriggerDescriptor)

Aggregations

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