use of org.apache.derby.iapi.sql.compile.CompilerContext 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.CompilerContext in project derby by apache.
the class AggregateNode method bindExpression.
/**
* Bind this operator. Determine the type of the subexpression,
* and pass that into the UserAggregate.
*
* @param fromList The query's FROM list
* @param subqueryList The subquery list being built as we find SubqueryNodes
* @param aggregates The aggregate list being built as we find AggregateNodes
*
* @return The new top of the expression tree.
*
* @exception StandardException Thrown on error
*/
@Override
ValueNode bindExpression(FromList fromList, SubqueryList subqueryList, List<AggregateNode> aggregates) throws StandardException {
DataDictionary dd = getDataDictionary();
DataTypeDescriptor dts = null;
ClassFactory cf;
cf = getClassFactory();
classInspector = cf.getClassInspector();
boolean noSchema = true;
if (userAggregateName != null) {
noSchema = (userAggregateName.getSchemaName() == null);
userAggregateName.bind();
}
// bind it now.
if (userAggregateName != null && uad == null) {
String schemaName = userAggregateName.getSchemaName();
AliasDescriptor ad = resolveAggregate(dd, getSchemaDescriptor(schemaName, true), userAggregateName.getTableName(), noSchema);
if (ad == null) {
throw StandardException.newException(SQLState.LANG_OBJECT_NOT_FOUND, AliasDescriptor.getAliasType(AliasInfo.ALIAS_TYPE_AGGREGATE_AS_CHAR), userAggregateName.getTableName());
}
setUserDefinedAggregate(new UserAggregateDefinition(ad));
aggregateName = ad.getJavaClassName();
}
instantiateAggDef();
// if this is a user-defined aggregate
if (isUserDefinedAggregate()) {
AliasDescriptor ad = ((UserAggregateDefinition) uad).getAliasDescriptor();
boolean isModernBuiltinAggregate = SchemaDescriptor.STD_SYSTEM_SCHEMA_NAME.equals(ad.getSchemaName());
if (distinct && isModernBuiltinAggregate) {
throw StandardException.newException(SQLState.LANG_BAD_DISTINCT_AGG);
}
// set up dependency on the user-defined aggregate and compile a check for USAGE
// priv if needed
getCompilerContext().createDependency(ad);
if (isPrivilegeCollectionRequired()) {
//
if (!isModernBuiltinAggregate) {
getCompilerContext().addRequiredUsagePriv(ad);
}
}
}
// Add ourselves to the list of aggregates before we do anything else.
aggregates.add(this);
CompilerContext cc = getCompilerContext();
// operand being null means a count(*)
if (operand != null) {
int previousReliability = orReliability(CompilerContext.AGGREGATE_RESTRICTION);
bindOperand(fromList, subqueryList, aggregates);
cc.setReliability(previousReliability);
/*
** Make sure that we don't have an aggregate
** IMMEDIATELY below us. Don't search below
** any ResultSetNodes.
*/
HasNodeVisitor visitor = new HasNodeVisitor(this.getClass(), ResultSetNode.class);
operand.accept(visitor);
if (visitor.hasNode()) {
throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_CONTAINS_AGGREGATE, getSQLName());
}
// Also forbid any window function inside an aggregate unless in
// subquery, cf. SQL 2003, section 10.9, SR 7 a).
SelectNode.checkNoWindowFunctions(operand, aggregateName);
/*
** Check the type of the operand. Make sure that the user
** defined aggregate can handle the operand datatype.
*/
dts = operand.getTypeServices();
/* Convert count(nonNullableColumn) to count(*) */
if (uad instanceof CountAggregateDefinition && !dts.isNullable()) {
setOperator(aggregateName);
setMethodName(aggregateName);
}
/*
** If we have a distinct, then the value expression
** MUST implement Orderable because we are going
** to process it using it as part of a sort.
*/
if (distinct) {
/*
** For now, we check to see if orderable() returns
** true for this type. In the future we may need
** to check to see if the type implements Orderable
**
*/
if (!operand.getTypeId().orderable(cf)) {
throw StandardException.newException(SQLState.LANG_COLUMN_NOT_ORDERABLE_DURING_EXECUTION, dts.getTypeId().getSQLTypeName());
}
}
/*
** Don't allow an untyped null
*/
if (operand instanceof UntypedNullConstantNode) {
throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_BAD_TYPE_NULL, getSQLName());
}
}
/*
** Ask the aggregate definition whether it can handle
** the input datatype.
*/
aggregatorClassName = new StringBuffer();
DataTypeDescriptor resultType = uad.getAggregator(dts, aggregatorClassName);
if (resultType == null) {
throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_BAD_TYPE, getSQLName(), operand.getTypeId().getSQLTypeName());
}
// coerced to the expected input type of the aggregator.
if (isUserDefinedAggregate()) {
ValueNode castNode = ((UserAggregateDefinition) uad).castInputValue(operand, getContextManager());
if (castNode != null) {
operand = castNode.bindExpression(fromList, subqueryList, aggregates);
}
}
checkAggregatorClassName(aggregatorClassName.toString());
setType(resultType);
return this;
}
use of org.apache.derby.iapi.sql.compile.CompilerContext in project derby by apache.
the class AggregateNode method replaceAggregatesWithColumnReferences.
/**
* Replace aggregates in the expression tree with a ColumnReference to
* that aggregate, append the aggregate to the supplied RCL (assumed to
* be from the child ResultSetNode) and return the ColumnReference.
* This is useful for pushing aggregates in the Having clause down to
* the user's select at parse time. It is also used for moving around
* Aggregates in the select list when creating the Group By node. In
* that case it is called <B> after </B> bind time, so we need to create
* the column differently.
*
* @param rcl The RCL to append to.
* @param tableNumber The tableNumber for the new ColumnReference
*
* @return ValueNode The (potentially) modified tree.
*
* @exception StandardException Thrown on error
*/
ValueNode replaceAggregatesWithColumnReferences(ResultColumnList rcl, int tableNumber) throws StandardException {
/*
** This call is idempotent. Do
** the right thing if we have already
** replaced ourselves.
*/
if (generatedRef == null) {
String generatedColName;
CompilerContext cc = getCompilerContext();
generatedColName = "SQLCol" + cc.getNextColumnNumber();
generatedRC = new ResultColumn(generatedColName, this, getContextManager());
generatedRC.markGenerated();
/*
** Parse time.
*/
generatedRef = new ColumnReference(generatedRC.getName(), null, getContextManager());
// RESOLVE - unknown nesting level, but not correlated, so nesting levels must be 0
generatedRef.setSource(generatedRC);
generatedRef.setNestingLevel(0);
generatedRef.setSourceLevel(0);
if (tableNumber != -1) {
generatedRef.setTableNumber(tableNumber);
}
rcl.addResultColumn(generatedRC);
/*
** Mark the ColumnReference as being generated to replace
** an aggregate
*/
generatedRef.markGeneratedToReplaceAggregate();
} else {
rcl.addResultColumn(generatedRC);
}
return generatedRef;
}
use of org.apache.derby.iapi.sql.compile.CompilerContext in project derby by apache.
the class QueryTreeNode method resolveTableToSynonym.
/**
* Resolve table/view reference to a synonym. May have to follow a synonym chain.
*
* @param tabName to match for a synonym
*
* @return Synonym TableName if a match is found, NULL otherwise.
*
* @exception StandardException Thrown on error
*/
TableName resolveTableToSynonym(TableName tabName) throws StandardException {
DataDictionary dd = getDataDictionary();
String nextSynonymTable = tabName.getTableName();
String nextSynonymSchema = tabName.getSchemaName();
boolean found = false;
CompilerContext cc = getCompilerContext();
// the following loop shouldn't loop forever.
for (; ; ) {
SchemaDescriptor nextSD = getSchemaDescriptor(nextSynonymSchema, false);
if (nextSD == null || nextSD.getUUID() == null)
break;
AliasDescriptor nextAD = dd.getAliasDescriptor(nextSD.getUUID().toString(), nextSynonymTable, AliasInfo.ALIAS_NAME_SPACE_SYNONYM_AS_CHAR);
if (nextAD == null)
break;
/* Query is dependent on the AliasDescriptor */
cc.createDependency(nextAD);
found = true;
SynonymAliasInfo info = ((SynonymAliasInfo) nextAD.getAliasInfo());
nextSynonymTable = info.getSynonymTable();
nextSynonymSchema = info.getSynonymSchema();
}
if (!found)
return null;
TableName tableName = new TableName(nextSynonymSchema, nextSynonymTable, getContextManager());
return tableName;
}
use of org.apache.derby.iapi.sql.compile.CompilerContext in project derby by apache.
the class QueryTreeNode method parseStatementOrSearchCondition.
/**
* Parse a full SQL statement or a fragment representing a {@code <search
* condition>}. This is a worker method that contains common logic for
* {@link #parseStatement} and {@link #parseSearchCondition}.
*
* @param sql the SQL statement or fragment to parse
* @param internalSQL {@code true} if it is allowed to contain internal
* syntax, {@code false} otherwise
* @param isStatement {@code true} if {@code sql} is a full SQL statement,
* {@code false} if it is a fragment
* @return a parse tree
* @throws StandardException if an error happens while parsing
*/
private Visitable parseStatementOrSearchCondition(String sql, boolean internalSQL, boolean isStatement) throws StandardException {
/*
** Get a new compiler context, so the parsing of the text
** doesn't mess up anything in the current context
*/
LanguageConnectionContext lcc = getLanguageConnectionContext();
CompilerContext newCC = lcc.pushCompilerContext();
if (internalSQL)
newCC.setReliability(CompilerContext.INTERNAL_SQL_LEGAL);
try {
Parser p = newCC.getParser();
return isStatement ? p.parseStatement(sql) : p.parseSearchCondition(sql);
} finally {
lcc.popCompilerContext(newCC);
}
}
Aggregations