use of org.apache.derby.iapi.sql.compile.Visitable in project derby by apache.
the class TriggerDescriptor method getSPS.
/**
* Get the SPS for the triggered SQL statement or the WHEN clause.
*
* @param lcc the LanguageConnectionContext to use
* @param isWhenClause {@code true} if the SPS for the WHEN clause is
* requested, {@code false} if it is the triggered SQL statement
* @return the requested SPS
* @throws StandardException if an error occurs
*/
private SPSDescriptor getSPS(LanguageConnectionContext lcc, boolean isWhenClause) throws StandardException {
DataDictionary dd = getDataDictionary();
SPSDescriptor sps = isWhenClause ? whenSPS : actionSPS;
UUID spsId = isWhenClause ? whenSPSId : actionSPSId;
String originalSQL = isWhenClause ? whenClauseText : triggerDefinition;
if (sps == null) {
// bug 4821 - do the sysstatement look up in a nested readonly
// transaction rather than in the user transaction. Because of
// this, the nested compile transaction which is attempting to
// compile the trigger will not run into any locking issues with
// the user transaction for sysstatements.
lcc.beginNestedTransaction(true);
sps = dd.getSPSDescriptor(spsId);
lcc.commitNestedTransaction();
}
// We need to regenerate the trigger action sql if
// 1)the trigger is found to be invalid,
// 2)the trigger is defined at row level (that is the only kind of
// trigger which allows reference to individual columns from
// old/new row)
// 3)the trigger action plan has columns that reference
// old/new row columns(if we are working with pre-10.9 db,
// meaning we are in soft-upgrade mode, then we won't have
// information about the actual trigger action columns since
// we didn't keep that info in those releases. For such dbs,
// we will just check if they are using REFERENCING OLD and/or
// NEW clause.)
// This code was added as part of DERBY-4874 where the Alter table
// had changed the length of a varchar column from varchar(30) to
// varchar(64) but the trigger action plan continued to use varchar(30).
// To fix varchar(30) in trigger action sql to varchar(64), we need
// to regenerate the trigger action sql. This new trigger action sql
// will then get updated into SYSSTATEMENTS table.
boolean in10_9_orHigherVersion = dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_9, null);
boolean usesReferencingClause = (in10_9_orHigherVersion) ? referencedColsInTriggerAction != null : (referencingOld || referencingNew);
if ((!sps.isValid() || (sps.getPreparedStatement() == null)) && isRow && usesReferencingClause) {
CompilerContext newCC = lcc.pushCompilerContext(dd.getSchemaDescriptor(sps.getCompSchemaId(), null));
Parser pa = newCC.getParser();
Visitable stmtnode = isWhenClause ? pa.parseSearchCondition(originalSQL) : pa.parseStatement(originalSQL);
lcc.popCompilerContext(newCC);
int[] cols;
cols = dd.examineTriggerNodeAndCols(stmtnode, oldReferencingName, newReferencingName, originalSQL, referencedCols, referencedColsInTriggerAction, 0, getTableDescriptor(), -1, false, null);
String newText = dd.getTriggerActionString(stmtnode, oldReferencingName, newReferencingName, originalSQL, referencedCols, referencedColsInTriggerAction, 0, getTableDescriptor(), -1, false, null, cols);
if (isWhenClause) {
// The WHEN clause is not a full SQL statement, just a search
// condition, so we need to turn it into a statement in order
// to create an SPS.
newText = "VALUES " + newText;
}
sps.setText(newText);
// By this point, we are finished transforming the trigger action if
// it has any references to old/new transition variables.
}
return sps;
}
use of org.apache.derby.iapi.sql.compile.Visitable in project derby by apache.
the class ResultSetNode method parseDefault.
/**
* Parse a default and turn it into a query tree.
*
* @param defaultText Text of Default.
*
* @return The parsed default as a query tree.
*
* @exception StandardException Thrown on failure
*/
public ValueNode parseDefault(String defaultText) throws StandardException {
Parser p;
ValueNode defaultTree;
LanguageConnectionContext lcc = getLanguageConnectionContext();
/* Get a Statement to pass to the parser */
/* We're all set up to parse. We have to build a compilable SQL statement
* before we can parse - So, we goober up a VALUES defaultText.
*/
String values = "VALUES " + defaultText;
/*
** Get a new compiler context, so the parsing of the select statement
** doesn't mess up anything in the current context (it could clobber
** the ParameterValueSet, for example).
*/
CompilerContext newCC = lcc.pushCompilerContext();
p = newCC.getParser();
/* Finally, we can call the parser */
// Since this is always nested inside another SQL statement, so topLevel flag
// should be false
Visitable qt = p.parseStatement(values);
if (SanityManager.DEBUG) {
if (!(qt instanceof CursorNode)) {
SanityManager.THROWASSERT("qt expected to be instanceof CursorNode, not " + qt.getClass().getName());
}
CursorNode cn = (CursorNode) qt;
if (!(cn.getResultSetNode() instanceof RowResultSetNode)) {
SanityManager.THROWASSERT("cn.getResultSetNode() expected to be instanceof RowResultSetNode, not " + cn.getResultSetNode().getClass().getName());
}
}
defaultTree = ((CursorNode) qt).getResultSetNode().getResultColumns().elementAt(0).getExpression();
lcc.popCompilerContext(newCC);
return defaultTree;
}
use of org.apache.derby.iapi.sql.compile.Visitable in project derby by apache.
the class DMLModStatementNode method parseCheckConstraint.
/**
* Parse a check constraint and turn it into a query tree.
*
* @param checkConstraintText Text of CHECK CONSTRAINT.
* @param td The TableDescriptor for the table the the constraint is on.
*
* @return The parsed check constraint as a query tree.
*
* @exception StandardException Thrown on failure
*/
public ValueNode parseCheckConstraint(String checkConstraintText, TableDescriptor td) throws StandardException {
Parser p;
ValueNode checkTree;
LanguageConnectionContext lcc = getLanguageConnectionContext();
/* Get a Statement to pass to the parser */
/* We're all set up to parse. We have to build a compile SQL statement
* before we can parse - we just have a WHERE clause right now.
* So, we goober up a SELECT * FROM table WHERE checkDefs.
*/
String select = "SELECT * FROM " + td.getQualifiedName() + " WHERE " + checkConstraintText;
/*
** Get a new compiler context, so the parsing of the select statement
** doesn't mess up anything in the current context (it could clobber
** the ParameterValueSet, for example).
*/
CompilerContext newCC = lcc.pushCompilerContext();
p = newCC.getParser();
/* Finally, we can call the parser */
// Since this is always nested inside another SQL statement, so topLevel flag
// should be false
Visitable qt = p.parseStatement(select);
if (SanityManager.DEBUG) {
if (!(qt instanceof CursorNode)) {
SanityManager.THROWASSERT("qt expected to be instanceof CursorNode, not " + qt.getClass().getName());
}
CursorNode cn = (CursorNode) qt;
if (!(cn.getResultSetNode() instanceof SelectNode)) {
SanityManager.THROWASSERT("cn.getResultSetNode() expected to be instanceof SelectNode, not " + cn.getResultSetNode().getClass().getName());
}
}
checkTree = ((SelectNode) ((CursorNode) qt).getResultSetNode()).getWhereClause();
lcc.popCompilerContext(newCC);
return checkTree;
}
use of org.apache.derby.iapi.sql.compile.Visitable in project derby by apache.
the class AlterTableConstantAction method columnDroppedAndTriggerDependencies.
// For the trigger, get the trigger action sql provided by the user
// in the create trigger sql. This sql is saved in the system
// table. Since a column has been dropped from the trigger table,
// the trigger action sql may not be valid anymore. To establish
// that, we need to regenerate the internal representation of that
// sql and bind it again.
//
// This method is called both on the WHEN clause (if one exists) and the
// triggered SQL statement of the trigger action.
//
// Return true if the trigger was dropped by this method (if cascade is
// true and it turns out the trigger depends on the column being dropped),
// or false otherwise.
private boolean columnDroppedAndTriggerDependencies(TriggerDescriptor trd, UUID spsUUID, boolean isWhenClause, boolean cascade, String columnName) throws StandardException {
dd.dropTriggerDescriptor(trd, tc);
// Here we get the trigger action sql and use the parser to build
// the parse tree for it.
SchemaDescriptor compSchema = dd.getSchemaDescriptor(dd.getSPSDescriptor(spsUUID).getCompSchemaId(), null);
CompilerContext newCC = lcc.pushCompilerContext(compSchema);
Parser pa = newCC.getParser();
String originalSQL = isWhenClause ? trd.getWhenClauseText() : trd.getTriggerDefinition();
Visitable node = isWhenClause ? pa.parseSearchCondition(originalSQL) : pa.parseStatement(originalSQL);
lcc.popCompilerContext(newCC);
// Do not delete following. We use this in finally clause to
// determine if the CompilerContext needs to be popped.
newCC = null;
try {
// Regenerate the internal representation for the trigger action
// sql using the ColumnReference classes in the parse tree. It
// will catch dropped column getting used in trigger action sql
// through the REFERENCING clause(this can happen only for the
// the triggers created prior to 10.7. Trigger created with
// 10.7 and higher keep track of trigger action column used
// through the REFERENCING clause in system table and hence
// use of dropped column will be detected earlier in this
// method for such triggers).
//
// We might catch errors like following during this step.
// Say that following pre-10.7 trigger exists in the system and
// user is dropping column c11. During the regeneration of the
// internal trigger action sql format, we will catch that
// column oldt.c11 does not exist anymore
// CREATE TRIGGER DERBY4998_SOFT_UPGRADE_RESTRICT_tr1
// AFTER UPDATE OF c12
// ON DERBY4998_SOFT_UPGRADE_RESTRICT REFERENCING OLD AS oldt
// FOR EACH ROW
// SELECT oldt.c11 from DERBY4998_SOFT_UPGRADE_RESTRICT
SPSDescriptor sps = isWhenClause ? trd.getWhenClauseSPS(lcc) : trd.getActionSPS(lcc);
int[] referencedColsInTriggerAction = new int[td.getNumberOfColumns()];
java.util.Arrays.fill(referencedColsInTriggerAction, -1);
String newText = dd.getTriggerActionString(node, trd.getOldReferencingName(), trd.getNewReferencingName(), originalSQL, trd.getReferencedCols(), referencedColsInTriggerAction, 0, trd.getTableDescriptor(), trd.getTriggerEventMask(), true, null, null);
if (isWhenClause) {
// The WHEN clause is not a full SQL statement, just a search
// condition, so we need to turn it into a statement in order
// to create an SPS.
newText = "VALUES " + newText;
}
sps.setText(newText);
// Now that we have the internal format of the trigger action sql,
// bind that sql to make sure that we are not using colunm being
// dropped in the trigger action sql directly (ie not through
// REFERENCING clause.
// eg
// create table atdc_12 (a integer, b integer);
// create trigger atdc_12_trigger_1 after update of a
// on atdc_12 for each row select a,b from atdc_12
// Drop one of the columns used in the trigger action
// alter table atdc_12 drop column b
// Following rebinding of the trigger action sql will catch the use
// of column b in trigger atdc_12_trigger_1
newCC = lcc.pushCompilerContext(compSchema);
newCC.setReliability(CompilerContext.INTERNAL_SQL_LEGAL);
pa = newCC.getParser();
StatementNode stmtnode = (StatementNode) pa.parseStatement(newText);
// need a current dependent for bind
newCC.setCurrentDependent(sps.getPreparedStatement());
stmtnode.bindStatement();
} catch (StandardException se) {
// Ane drop column ATDC_13_TAB3.c12 is issued
if (se.getMessageId().equals(SQLState.LANG_COLUMN_NOT_FOUND) || (se.getMessageId().equals(SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE) || (se.getMessageId().equals(SQLState.LANG_DB2_INVALID_COLS_SPECIFIED) || (se.getMessageId().equals(SQLState.LANG_TABLE_NOT_FOUND))))) {
if (cascade) {
trd.drop(lcc);
activation.addWarning(StandardException.newWarning(SQLState.LANG_TRIGGER_DROPPED, trd.getName(), td.getName()));
return true;
} 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());
}
} else
throw se;
} finally {
if (newCC != null)
lcc.popCompilerContext(newCC);
}
// If we are here, then it means that the column being dropped
// is not getting used in the trigger action.
//
// We have recreated the trigger action SPS and recollected the
// column positions for trigger columns and trigger action columns
// getting accessed through REFERENCING clause because
// drop column can affect the column positioning of existing
// columns in the table. We will save that in the system table.
dd.addDescriptor(trd, sd, DataDictionary.SYSTRIGGERS_CATALOG_NUM, false, tc);
return false;
}
use of org.apache.derby.iapi.sql.compile.Visitable in project derby by apache.
the class QueryTreeNode method accept.
/**
* Accept a visitor, and call {@code v.visit()} on child nodes as
* necessary. Sub-classes should not override this method, but instead
* override the {@link #acceptChildren(Visitor)} method.
*
* @param v the visitor
*
* @exception StandardException on error
*/
public final Visitable accept(Visitor v) throws StandardException {
final boolean childrenFirst = v.visitChildrenFirst(this);
final boolean skipChildren = v.skipChildren(this);
if (childrenFirst && !skipChildren && !v.stopTraversal()) {
acceptChildren(v);
}
final Visitable ret = v.stopTraversal() ? this : v.visit(this);
if (!childrenFirst && !skipChildren && !v.stopTraversal()) {
acceptChildren(v);
}
return ret;
}
Aggregations