Search in sources :

Example 1 with ColumnReference

use of org.apache.derby.impl.sql.compile.ColumnReference in project derby by apache.

the class DataDictionaryImpl method getTransitionVariables.

/**
 * Get all columns that reference transition variables in triggers.
 * The columns should be returned in the same order as in the SQL text.
 *
 * @param node the node in which to look for transition variables
 * @param oldReferencingName the name of the old transition variable
 * @param newReferencingName the name of the new transition variable
 * @return all references to transition variables
 */
private static SortedSet<ColumnReference> getTransitionVariables(Visitable node, String oldReferencingName, String newReferencingName) throws StandardException {
    // First get all column references.
    SortedSet<ColumnReference> refs = ((QueryTreeNode) node).getOffsetOrderedNodes(ColumnReference.class);
    // Then remove all that are not referencing a transition variable.
    Iterator<ColumnReference> it = refs.iterator();
    while (it.hasNext()) {
        TableName tableName = it.next().getQualifiedTableName();
        if (!isTransitionVariable(tableName, oldReferencingName, newReferencingName)) {
            it.remove();
        }
    }
    // variables.
    return refs;
}
Also used : TableName(org.apache.derby.impl.sql.compile.TableName) QueryTreeNode(org.apache.derby.impl.sql.compile.QueryTreeNode) ColumnReference(org.apache.derby.impl.sql.compile.ColumnReference)

Example 2 with ColumnReference

use of org.apache.derby.impl.sql.compile.ColumnReference in project derby by apache.

the class DataDictionaryImpl method examineTriggerNodeAndCols.

/**
 * Get the trigger action string associated with the trigger after the
 * references to old/new transition tables/variables in trigger action
 * sql provided by CREATE TRIGGER have been transformed eg
 *		DELETE FROM t WHERE c = old.c
 * turns into
 *	DELETE FROM t WHERE c = org.apache.derby.iapi.db.Factory::
 *		getTriggerExecutionContext().getOldRow().
 *      getInt(columnNumberFor'C'inRuntimeResultset)
 * or
 *	DELETE FROM t WHERE c in (SELECT c FROM OLD)
 * turns into
 *	DELETE FROM t WHERE c in
 *		(SELECT c FROM new TriggerOldTransitionTable OLD)
 *
 * @param actionStmt This is needed to get access to the various nodes
 * 	generated by the Parser for the trigger action sql. These nodes will be
 * 	used to find REFERENCEs column nodes.
 *
 * @param oldReferencingName The name specified by the user for REFERENCEs
 * 	to old row columns
 *
 * @param newReferencingName The name specified by the user for REFERENCEs
 * 	to new row columns
 *
 * @param triggerDefinition The original trigger action text provided by
 * 	the user during CREATE TRIGGER time.
 *
 * @param referencedCols Trigger is defined on these columns (will be null
 *   in case of INSERT AND DELETE Triggers. Can also be null for DELETE
 *   Triggers if UPDATE trigger is not defined on specific column(s))
 *
 * @param referencedColsInTriggerAction	what columns does the trigger
 * 	action reference through old/new transition variables (may be null)
 *
 * @param actionOffset offset of start of action clause
 *
 * @param triggerTableDescriptor Table descriptor for trigger table
 *
 * @param triggerEventMask TriggerDescriptor.TRIGGER_EVENT_XXX
 *
 * @param createTriggerTime True if here for CREATE TRIGGER,
 * 	false if here because an invalidated row level trigger with
 *  REFERENCEd columns has been fired and hence trigger action
 *  sql associated with SPSDescriptor may be invalid too.
 *
 * @return Transformed trigger action sql
 * @throws StandardException
 */
public int[] examineTriggerNodeAndCols(Visitable actionStmt, String oldReferencingName, String newReferencingName, String triggerDefinition, int[] referencedCols, int[] referencedColsInTriggerAction, int actionOffset, TableDescriptor triggerTableDescriptor, int triggerEventMask, boolean createTriggerTime, List<int[]> replacements) throws StandardException {
    // If we are dealing with database created in 10.8 and prior,
    // then we must be in soft upgrade mode. For such databases,
    // we want to generate trigger action sql which assumes that
    // all columns are getting read from the trigger table. We
    // need to do this to maintain backward compatibility.
    boolean in10_9_orHigherVersion = checkVersion(DataDictionary.DD_VERSION_DERBY_10_9, null);
    StringBuilder newText = new StringBuilder();
    int start = 0;
    // Total Number of columns in the trigger table
    int numberOfColsInTriggerTable = triggerTableDescriptor.getNumberOfColumns();
    // The purpose of following array(triggerColsAndTriggerActionCols)
    // is to identify all the trigger columns and all the columns from
    // the trigger action which are referenced though old/new
    // transition variables(in other words, accessed through the
    // REFERENCING clause section of CREATE TRIGGER sql). This array
    // will be initialized to -1 at the beginning. By the end of this
    // method, all the columns referenced by the trigger action
    // through the REFERENCING clause and all the trigger columns will
    // have their column positions in the trigger table noted in this
    // array.
    // eg
    // CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1
    // REFERENCING OLD AS oldt NEW AS newt
    // FOR EACH ROW UPDATE table2 SET c24=oldt.c14;
    // For the trigger above, triggerColsAndTriggerActionCols will
    // finally have [-1,2,-1,4,-1] This list will include all the
    // columns that need to be fetched into memory during trigger
    // execution. All the columns with their entries marked -1 will
    // not be read into memory because they are not referenced in the
    // trigger action through old/new transition variables and they are
    // not recognized as trigger columns.
    int[] triggerColsAndTriggerActionCols = new int[numberOfColsInTriggerTable];
    /**
     * It identifies all the trigger action columns and is initialized to -1.
     */
    int[] triggerActionColsOnly = new int[numberOfColsInTriggerTable];
    java.util.Arrays.fill(triggerActionColsOnly, -1);
    if (referencedCols == null) {
        // FOR EACH ROW UPDATE table2 SET c24=oldt.c14;
        for (int i = 0; i < numberOfColsInTriggerTable; i++) {
            triggerColsAndTriggerActionCols[i] = i + 1;
        }
    } else {
        // This means that this row level trigger is an UPDATE trigger
        // defined on specific column(s).
        java.util.Arrays.fill(triggerColsAndTriggerActionCols, -1);
        for (int i = 0; i < referencedCols.length; i++) {
            // Make a note of this trigger column's column position in
            // triggerColsAndTriggerActionCols. This will tell us that
            // this column needs to be read in when the trigger fires.
            // eg for the CREATE TRIGGER below, we will make a note of
            // column c12's position in triggerColsAndTriggerActionCols
            // eg
            // CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1
            // REFERENCING OLD AS oldt NEW AS newt
            // FOR EACH ROW UPDATE table2 SET c24=oldt.c14;
            triggerColsAndTriggerActionCols[referencedCols[i] - 1] = referencedCols[i];
        }
    }
    if (referencedColsInTriggerAction != null) {
        for (int i = 0; i < referencedColsInTriggerAction.length; i++) {
            if (referencedColsInTriggerAction[i] > 0)
                triggerColsAndTriggerActionCols[referencedColsInTriggerAction[i] - 1] = referencedColsInTriggerAction[i];
        }
    }
    /* we need to sort on position in string, beetle 4324
		 */
    SortedSet<ColumnReference> refs = getTransitionVariables(actionStmt, oldReferencingName, newReferencingName);
    if (createTriggerTime) {
        // usage of trigger action columns again in 10.9
        for (ColumnReference ref : refs) {
            TableName tableName = ref.getQualifiedTableName();
            checkInvalidTriggerReference(tableName.getTableName(), oldReferencingName, newReferencingName, triggerEventMask);
            String colName = ref.getColumnName();
            ColumnDescriptor triggerColDesc;
            // FOR EACH ROW UPDATE table2 SET c24=oldt.c14567;
            if ((triggerColDesc = triggerTableDescriptor.getColumnDescriptor(colName)) == null) {
                throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND, tableName + "." + colName);
            }
            if (in10_9_orHigherVersion) {
                int triggerColDescPosition = triggerColDesc.getPosition();
                triggerColsAndTriggerActionCols[triggerColDescPosition - 1] = triggerColDescPosition;
                triggerActionColsOnly[triggerColDescPosition - 1] = triggerColDescPosition;
                referencedColsInTriggerAction[triggerColDescPosition - 1] = triggerColDescPosition;
            }
        }
    } else {
        // REFERENCING clause. DERBY-4887
        if (referencedCols != null && referencedColsInTriggerAction != null) {
            for (int i = 0; i < referencedColsInTriggerAction.length; i++) {
                triggerColsAndTriggerActionCols[referencedColsInTriggerAction[i] - 1] = referencedColsInTriggerAction[i];
            }
        }
    }
    Arrays.sort(triggerColsAndTriggerActionCols);
    // Now that we know what columns we need for trigger columns and
    // trigger action columns, we can get rid of remaining -1 entries
    // for the remaining columns from trigger table.
    // eg
    // CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1
    // REFERENCING OLD AS oldt NEW AS newt
    // FOR EACH ROW UPDATE table2 SET c24=oldt.c14;
    // For the above trigger, before the justTheRequiredColumns() call,
    // the content of triggerColsAndTriggerActionCols array were as
    // follows [-1, 2, -1, 4, -1]
    // After the justTheRequiredColumns() call below,
    // triggerColsAndTriggerActionCols will have [2,4]. What this means
    // that, at run time, during trigger execution, these are the only
    // 2 column positions that will be read into memory from the
    // trigger table. The columns in other column positions are not
    // needed for trigger execution.
    triggerColsAndTriggerActionCols = justTheRequiredColumns(triggerColsAndTriggerActionCols, triggerTableDescriptor);
    return triggerColsAndTriggerActionCols;
}
Also used : TableName(org.apache.derby.impl.sql.compile.TableName) ColumnDescriptor(org.apache.derby.iapi.sql.dictionary.ColumnDescriptor) SQLLongint(org.apache.derby.iapi.types.SQLLongint) ColumnReference(org.apache.derby.impl.sql.compile.ColumnReference)

Example 3 with ColumnReference

use of org.apache.derby.impl.sql.compile.ColumnReference in project derby by apache.

the class DataDictionaryImpl method getTriggerActionString.

public String getTriggerActionString(Visitable actionStmt, String oldReferencingName, String newReferencingName, String triggerDefinition, int[] referencedCols, int[] referencedColsInTriggerAction, int actionOffset, TableDescriptor triggerTableDescriptor, int triggerEventMask, boolean createTriggerTime, List<int[]> replacements, int[] cols) throws StandardException {
    boolean in10_9_orHigherVersion = checkVersion(DataDictionary.DD_VERSION_DERBY_10_9, null);
    StringBuilder newText = new StringBuilder();
    int start = 0;
    // Total Number of columns in the trigger table
    int numberOfColsInTriggerTable = triggerTableDescriptor.getNumberOfColumns();
    int[] triggerColsAndTriggerActionCols = new int[numberOfColsInTriggerTable];
    SortedSet<ColumnReference> refs = getTransitionVariables(actionStmt, oldReferencingName, newReferencingName);
    triggerColsAndTriggerActionCols = cols;
    // (SELECT c FROM new TriggerOldTransitionTable OLD)
    for (ColumnReference ref : refs) {
        TableName tableName = ref.getQualifiedTableName();
        int tableBeginOffset = tableName.getBeginOffset() - actionOffset;
        String colName = ref.getColumnName();
        // Add whatever we've seen after the previous replacement.
        newText.append(triggerDefinition, start, tableBeginOffset);
        int colPositionInRuntimeResultSet = -1;
        ColumnDescriptor triggerColDesc = triggerTableDescriptor.getColumnDescriptor(colName);
        // column in the trigger table.
        if (triggerColDesc == null) {
            throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND, tableName + "." + colName);
        }
        int colPositionInTriggerTable = triggerColDesc.getPosition();
        // is 2. That is what the following code is doing.
        if (in10_9_orHigherVersion && triggerColsAndTriggerActionCols != null) {
            for (int j = 0; j < triggerColsAndTriggerActionCols.length; j++) {
                if (triggerColsAndTriggerActionCols[j] == colPositionInTriggerTable)
                    colPositionInRuntimeResultSet = j + 1;
            }
        } else
            colPositionInRuntimeResultSet = colPositionInTriggerTable;
        // Add the replacement code that accesses a value in the
        // transition variable.
        final int replacementOffset = newText.length();
        newText.append(genColumnReferenceSQL(triggerTableDescriptor, colName, tableName.getTableName(), tableName.getTableName().equals(oldReferencingName), colPositionInRuntimeResultSet));
        start = ref.getEndOffset() + 1 - actionOffset;
        if (replacements != null) {
            // Record that we have made a change.
            replacements.add(new int[] { // offset to replaced text
            tableBeginOffset, // offset to token after replaced text
            start, // offset to replacement
            replacementOffset, // offset to token after replacement
            newText.length() });
        }
    }
    // By this point, we are finished transforming the trigger action if
    // it has any references to old/new transition variables.
    newText.append(triggerDefinition, start, triggerDefinition.length());
    return newText.toString();
}
Also used : TableName(org.apache.derby.impl.sql.compile.TableName) ColumnDescriptor(org.apache.derby.iapi.sql.dictionary.ColumnDescriptor) SQLLongint(org.apache.derby.iapi.types.SQLLongint) ColumnReference(org.apache.derby.impl.sql.compile.ColumnReference)

Aggregations

ColumnReference (org.apache.derby.impl.sql.compile.ColumnReference)3 TableName (org.apache.derby.impl.sql.compile.TableName)3 ColumnDescriptor (org.apache.derby.iapi.sql.dictionary.ColumnDescriptor)2 SQLLongint (org.apache.derby.iapi.types.SQLLongint)2 QueryTreeNode (org.apache.derby.impl.sql.compile.QueryTreeNode)1