if (ref.getBeginOffset() == -1)
{
continue;
}
TableName tableName = ref.getTableNameNode();
if ((tableName == null) ||
((oldReferencingName == null || !oldReferencingName.equals(tableName.getTableName())) &&
(newReferencingName == null || !newReferencingName.equals(tableName.getTableName()))))
{
continue;
}
if (tableName.getBeginOffset() == -1)
{
continue;
}
checkInvalidTriggerReference(tableName.getTableName(),
oldReferencingName,
newReferencingName,
triggerEventMask);
String colName = ref.getColumnName();
ColumnDescriptor triggerColDesc;
//Following will catch the case where an invalid column is
//used in trigger action through the REFERENCING clause. The
//following tigger is trying to use oldt.c13 but there is no
//column c13 in trigger table table1
//CREATE TRIGGER tr1 AFTER UPDATE OF c12 ON table1
// REFERENCING OLD AS oldt NEW AS newt
// 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_7_orHigherVersion) {
int triggerColDescPosition = triggerColDesc.getPosition();
triggerColsAndTriggerActionCols[triggerColDescPosition-1]=triggerColDescPosition;
triggerActionColsOnly[triggerColDescPosition-1]=triggerColDescPosition;
referencedColsInTriggerAction[triggerColDescPosition-1] = triggerColDescPosition;
}
}
} else {
//We are here because we have come across an invalidated trigger
//which is being fired. This code gets called for such a trigger
//only if it is a row level trigger with REFERENCEs clause
//
// referencedColsInTriggerAction can be null if trigger action
// does not use any columns through REFERENCING clause. This can
// happen when we are coming here through ALTER TABLE DROP COLUMN
// and the trigger being rebuilt does not use any columns through
// REFERENCING clause. DERBY-4887
if (referencedCols != null && referencedColsInTriggerAction != null){
for (int i = 0; i < referencedColsInTriggerAction.length; i++)
{
triggerColsAndTriggerActionCols[referencedColsInTriggerAction[i]-1] = referencedColsInTriggerAction[i];
}
}
}
//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);
//This is where we do the actual transformation of trigger action
//sql. An eg of that is
// 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)
for (int i = 0; i < cols.length; i++)
{
ColumnReference ref = (ColumnReference) cols[i];
/*
** Only occurrences of those OLD/NEW transition tables/variables
** are of interest here. There may be intermediate nodes in the
** parse tree that have its own RCL which contains copy of
** column references(CR) from other nodes. e.g.:
**
** CREATE TRIGGER tt
** AFTER INSERT ON x
** REFERENCING NEW AS n
** FOR EACH ROW
** INSERT INTO y VALUES (n.i), (999), (333);
**
** The above trigger action will result in InsertNode that
** contains a UnionNode of RowResultSetNodes. The UnionNode
** will have a copy of the CRs from its left child and those CRs
** will not have its beginOffset set which indicates they are
** not relevant for the conversion processing here, so we can
** safely skip them.
*/
if (ref.getBeginOffset() == -1)
{
continue;
}
TableName tableName = ref.getTableNameNode();
if ((tableName == null) ||
((oldReferencingName == null || !oldReferencingName.equals(tableName.getTableName())) &&
(newReferencingName == null || !newReferencingName.equals(tableName.getTableName()))))
{
continue;
}
int tokBeginOffset = tableName.getBeginOffset();
int tokEndOffset = tableName.getEndOffset();
if (tokBeginOffset == -1)
{
continue;
}
String colName = ref.getColumnName();
int columnLength = ref.getEndOffset() - ref.getBeginOffset() + 1;
newText.append(triggerDefinition.substring(start, tokBeginOffset-actionOffset));
int colPositionInRuntimeResultSet = -1;
ColumnDescriptor triggerColDesc = triggerTableDescriptor.getColumnDescriptor(colName);
//DERBY-5121 We can come here if the column being used in trigger
// action is getting dropped and we have come here through that
// ALTER TABLE DROP COLUMN. In that case, we will not find the
// column in the trigger table.
if (triggerColDesc == null) {
throw StandardException.newException(
SQLState.LANG_COLUMN_NOT_FOUND, tableName+"."+colName);
}
int colPositionInTriggerTable = triggerColDesc.getPosition();
//This part of code is little tricky and following will help
//understand what mapping is happening here.
//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, 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. But
//even though column positions in original trigger table are 2
//and 4, their relative column positions in the columns read at
//execution time is really [1,2]. At run time, when the trigger
//gets fired, column position 2 from the trigger table will be
//read as the first column and column position 4 from the
//trigger table will be read as the second column. And those
//relative column positions at runtime is what should be used
//during trigger action conversion from
//UPDATE table2 SET c24=oldt.c14
//to
//UPDATE table2 SET c24=
// org.apache.derby.iapi.db.Factory::getTriggerExecutionContext().
// getOldRow().getInt(2)
//Note that the generated code above refers to column c14 from
//table1 by position 2 rather than position 4. Column c14's
//column position in table1 is 4 but in the relative columns
//that will be fetched during trigger execution, it's position
//is 2. That is what the following code is doing.
if (in10_7_orHigherVersion && triggerColsAndTriggerActionCols != null){
for (int j=0; j<triggerColsAndTriggerActionCols.length; j++){
if (triggerColsAndTriggerActionCols[j] == colPositionInTriggerTable)
colPositionInRuntimeResultSet=j+1;
}
} else
colPositionInRuntimeResultSet=colPositionInTriggerTable;
newText.append(genColumnReferenceSQL(triggerTableDescriptor, colName,
tableName.getTableName(),
tableName.getTableName().equals(oldReferencingName),
colPositionInRuntimeResultSet));
start = tokEndOffset- actionOffset + columnLength + 2;
}
//By this point, we are finished transforming the trigger action if
//it has any references to old/new transition variables.