use of org.apache.derby.iapi.sql.compile.CompilerContext in project derby by apache.
the class TableElementList method bindAndValidateGenerationClauses.
/**
* Bind and validate all of the generation clauses in this list against
* the specified FromList.
*
* @param sd Schema where the table lives.
* @param fromList The FromList in question.
* @param generatedColumns Bitmap of generated columns in the table. Vacuous for CREATE TABLE, but may be non-trivial for ALTER TABLE. This routine may set bits for new generated columns.
* @param baseTable Table descriptor if this is an ALTER TABLE statement.
*
* @exception StandardException Thrown on error
*/
void bindAndValidateGenerationClauses(SchemaDescriptor sd, FromList fromList, FormatableBitSet generatedColumns, TableDescriptor baseTable) throws StandardException {
FromBaseTable table = (FromBaseTable) fromList.elementAt(0);
ResultColumnList tableColumns = table.getResultColumns();
int columnCount = table.getResultColumns().size();
// complain if a generation clause references another generated column
findIllegalGenerationReferences(fromList, baseTable);
generatedColumns.grow(columnCount + 1);
CompilerContext cc = getCompilerContext();
ArrayList<AggregateNode> aggregates = new ArrayList<AggregateNode>();
for (TableElementNode element : this) {
ColumnDefinitionNode cdn;
GenerationClauseNode generationClauseNode;
ValueNode generationTree;
if (!(element instanceof ColumnDefinitionNode)) {
continue;
}
cdn = (ColumnDefinitionNode) element;
if (!cdn.hasGenerationClause()) {
continue;
}
generationClauseNode = cdn.getGenerationClauseNode();
// bind the generation clause
final int previousReliability = cc.getReliability();
ProviderList prevAPL = cc.getCurrentAuxiliaryProviderList();
try {
/* Each generation clause can have its own set of dependencies.
* These dependencies need to be shared with the prepared
* statement as well. We create a new auxiliary provider list
* for the generation clause, "push" it on the compiler context
* by swapping it with the current auxiliary provider list
* and the "pop" it when we're done by restoring the old
* auxiliary provider list.
*/
ProviderList apl = new ProviderList();
cc.setCurrentAuxiliaryProviderList(apl);
// Tell the compiler context to forbid subqueries and
// non-deterministic functions.
cc.setReliability(CompilerContext.GENERATION_CLAUSE_RESTRICTION);
generationTree = generationClauseNode.bindExpression(fromList, (SubqueryList) null, aggregates);
SelectNode.checkNoWindowFunctions(generationClauseNode, "generation clause");
//
// If the user did not declare a type for this column, then the column type defaults
// to the type of the generation clause.
// However, if the user did declare a type for this column, then the
// type of the generation clause must be assignable to the declared
// type.
//
DataTypeDescriptor generationClauseType = generationTree.getTypeServices();
DataTypeDescriptor declaredType = cdn.getType();
if (declaredType == null) {
cdn.setType(generationClauseType);
//
// Poke the type into the FromTable so that constraints will
// compile.
//
tableColumns.getResultColumn(cdn.getColumnName(), false).setType(generationClauseType);
//
// We skipped these steps earlier on because we didn't have
// a datatype. Now that we have a datatype, revisit these
// steps.
//
setCollationTypeOnCharacterStringColumn(sd, cdn);
cdn.checkUserType(table.getTableDescriptor());
} else {
TypeId declaredTypeId = declaredType.getTypeId();
TypeId resolvedTypeId = generationClauseType.getTypeId();
if (!getTypeCompiler(resolvedTypeId).convertible(declaredTypeId, false)) {
throw StandardException.newException(SQLState.LANG_UNASSIGNABLE_GENERATION_CLAUSE, cdn.getName(), resolvedTypeId.getSQLTypeName());
}
}
// no aggregates, please
if (!aggregates.isEmpty()) {
throw StandardException.newException(SQLState.LANG_AGGREGATE_IN_GENERATION_CLAUSE, cdn.getName());
}
/* Save the APL off in the constraint node */
if (apl.size() > 0) {
generationClauseNode.setAuxiliaryProviderList(apl);
}
} finally {
// Restore previous compiler state
cc.setCurrentAuxiliaryProviderList(prevAPL);
cc.setReliability(previousReliability);
}
/* We have a valid generation clause, now build an array of
* 1-based columnIds that the clause references.
*/
ResultColumnList rcl = table.getResultColumns();
int numReferenced = rcl.countReferencedColumns();
int[] generationClauseColumnReferences = new int[numReferenced];
int position = rcl.getPosition(cdn.getColumnName(), 1);
generatedColumns.set(position);
rcl.recordColumnReferences(generationClauseColumnReferences, 1);
String[] referencedColumnNames = new String[numReferenced];
for (int i = 0; i < numReferenced; i++) {
referencedColumnNames[i] = rcl.elementAt(generationClauseColumnReferences[i] - 1).getName();
}
String currentSchemaName = getLanguageConnectionContext().getCurrentSchemaName();
DefaultInfoImpl dii = new DefaultInfoImpl(generationClauseNode.getExpressionText(), referencedColumnNames, currentSchemaName);
cdn.setDefaultInfo(dii);
/* Clear the column references in the RCL so each generation clause
* starts with a clean list.
*/
rcl.clearColumnReferences();
}
}
use of org.apache.derby.iapi.sql.compile.CompilerContext in project derby by apache.
the class UpdateNode method addUpdatePriv.
/**
* Add UPDATE_PRIV on all columns on the left side of SET operators.
*/
private void addUpdatePriv(ArrayList<String> explicitlySetColumns) throws StandardException {
if (!isPrivilegeCollectionRequired()) {
return;
}
CompilerContext cc = getCompilerContext();
cc.pushCurrentPrivType(Authorizer.UPDATE_PRIV);
try {
for (String columnName : explicitlySetColumns) {
ColumnDescriptor cd = targetTableDescriptor.getColumnDescriptor(columnName);
cc.addRequiredColumnPriv(cd);
}
} finally {
cc.popCurrentPrivType();
}
}
use of org.apache.derby.iapi.sql.compile.CompilerContext in project derby by apache.
the class SelectNode method bindExpressions.
/**
* Bind the expressions in this SelectNode. This means binding the
* sub-expressions, as well as figuring out what the return type is
* for each expression.
*
* @param fromListParam FromList to use/append to.
*
* @exception StandardException Thrown on error
*/
@Override
void bindExpressions(FromList fromListParam) throws StandardException {
//
// Don't add USAGE privilege on user-defined types.
//
boolean wasSkippingTypePrivileges = getCompilerContext().skipTypePrivileges(true);
int fromListParamSize = fromListParam.size();
int fromListSize = fromList.size();
int numDistinctAggs;
if (SanityManager.DEBUG) {
SanityManager.ASSERT(fromList != null && getResultColumns() != null, "Both fromList and resultColumns are expected to be non-null");
}
for (int i = 0; i < qec.size(); i++) {
final OrderByList obl = qec.getOrderByList(i);
if (obl != null) {
obl.pullUpOrderByColumns(this);
}
}
/* NOTE - a lot of this code would be common to bindTargetExpression(),
* so we use a private boolean to share the code instead of duplicating
* it. bindTargetExpression() is responsible for toggling the boolean.
*/
if (!bindTargetListOnly) {
/* Bind the expressions in FromSubquerys, JoinNodes, etc. */
fromList.bindExpressions(fromListParam);
}
selectSubquerys = new SubqueryList(getContextManager());
selectAggregates = new ArrayList<AggregateNode>();
/* Splice our FromList on to the beginning of fromListParam, before binding
* the expressions, for correlated column resolution.
*/
for (int index = 0; index < fromListSize; index++) {
fromListParam.insertElementAt(fromList.elementAt(index), index);
}
// In preparation for resolving window references in expressions, we
// make the FromList carry the set of explicit window definitions.
//
// E.g. "select row_number () from r, .. from t window r as ()"
//
// Here the expression "row_number () from r" needs to be bound to r's
// definition. Window functions can also in-line window specifications,
// no resolution is necessary. See also
// WindowFunctionNode.bindExpression.
fromListParam.setWindows(windows);
getResultColumns().bindExpressions(fromListParam, selectSubquerys, selectAggregates);
/* We're done if we're only binding the target list.
* (After we restore the fromList, of course.)
*/
if (bindTargetListOnly) {
for (int index = 0; index < fromListSize; index++) {
fromListParam.removeElementAt(0);
}
return;
}
whereAggregates = new ArrayList<AggregateNode>();
whereSubquerys = new SubqueryList(getContextManager());
CompilerContext cc = getCompilerContext();
if (whereClause != null) {
cc.beginScope(CompilerContext.WHERE_SCOPE);
cc.pushCurrentPrivType(Authorizer.SELECT_PRIV);
int previousReliability = orReliability(CompilerContext.WHERE_CLAUSE_RESTRICTION);
whereClause = whereClause.bindExpression(fromListParam, whereSubquerys, whereAggregates);
cc.setReliability(previousReliability);
/* RESOLVE - Temporarily disable aggregates in the HAVING clause.
** (We may remove them in the parser anyway.)
** RESOLVE - Disable aggregates in the WHERE clause. Someday
** Aggregates will be allowed iff they are in a subquery
** of the having clause and they correlate to an outer
** query block. For now, aggregates are not supported
** in the WHERE clause at all.
** Note: a similar check is made in JoinNode.
*/
if (whereAggregates.size() > 0) {
throw StandardException.newException(SQLState.LANG_NO_AGGREGATES_IN_WHERE_CLAUSE);
}
/* If whereClause is a parameter, (where ?/where -?/where +?), then we should catch it and throw exception
*/
if (whereClause.isParameterNode())
throw StandardException.newException(SQLState.LANG_UNTYPED_PARAMETER_IN_WHERE_CLAUSE);
whereClause = whereClause.checkIsBoolean();
getCompilerContext().popCurrentPrivType();
cc.endScope(CompilerContext.WHERE_SCOPE);
checkNoWindowFunctions(whereClause, "WHERE");
}
if (havingClause != null) {
int previousReliability = orReliability(CompilerContext.HAVING_CLAUSE_RESTRICTION);
havingAggregates = new ArrayList<AggregateNode>();
havingSubquerys = new SubqueryList(getContextManager());
havingClause.bindExpression(fromListParam, havingSubquerys, havingAggregates);
havingClause = havingClause.checkIsBoolean();
checkNoWindowFunctions(havingClause, "HAVING");
cc.setReliability(previousReliability);
}
/* Restore fromList */
for (int index = 0; index < fromListSize; index++) {
fromListParam.removeElementAt(0);
}
if (SanityManager.DEBUG) {
SanityManager.ASSERT(fromListParam.size() == fromListParamSize, "fromListParam.size() = " + fromListParam.size() + ", expected to be restored to " + fromListParamSize);
SanityManager.ASSERT(fromList.size() == fromListSize, "fromList.size() = " + fromList.size() + ", expected to be restored to " + fromListSize);
}
/* If query is grouped, bind the group by list. */
if (groupByList != null) {
// We expect zero aggregates, so initialize the holder array
// with zero capacity.
ArrayList<AggregateNode> groupByAggregates = new ArrayList<AggregateNode>(0);
groupByList.bindGroupByColumns(this, groupByAggregates);
/*
** There should be no aggregates in the Group By list.
** We don't expect any, but just to be on the safe side
** we will check under sanity.
*/
if (SanityManager.DEBUG) {
SanityManager.ASSERT(groupByAggregates.isEmpty(), "Unexpected aggregate list generated by GROUP BY clause");
}
checkNoWindowFunctions(groupByList, "GROUP BY");
}
/* If ungrouped query with aggregates in SELECT list, verify
* that all result columns are valid aggregate expressions -
* no column references outside of an aggregate.
* If grouped query with aggregates in SELECT list, verify that all
* result columns are either grouping expressions or valid
* grouped aggregate expressions - the only column references
* allowed outside of an aggregate are columns in expressions in
* the group by list.
*/
if (groupByList != null || selectAggregates.size() > 0) {
VerifyAggregateExpressionsVisitor visitor = new VerifyAggregateExpressionsVisitor(groupByList);
getResultColumns().accept(visitor);
}
/*
** RESOLVE: for now, only one distinct aggregate is supported
** in the select list.
*/
numDistinctAggs = numDistinctAggregates(selectAggregates);
if (groupByList == null && numDistinctAggs > 1) {
throw StandardException.newException(SQLState.LANG_USER_AGGREGATE_MULTIPLE_DISTINCTS);
}
for (int i = 0; i < qec.size(); i++) {
final OrderByList obl = qec.getOrderByList(i);
if (obl != null) {
obl.bindOrderByColumns(this);
}
bindOffsetFetch(qec.getOffset(i), qec.getFetchFirst(i));
}
getCompilerContext().skipTypePrivileges(wasSkippingTypePrivileges);
}
use of org.apache.derby.iapi.sql.compile.CompilerContext in project derby by apache.
the class UserAggregateDefinition method getAggregator.
/**
* Determines the result datatype and verifies that the input datatype is correct.
*
* @param inputType the input type
* @param aggregatorClass (Output arg) the name of the Derby execution-time class which wraps the aggregate logic
*
* @return the result type of the user-defined aggregator
*/
public final DataTypeDescriptor getAggregator(DataTypeDescriptor inputType, StringBuffer aggregatorClass) throws StandardException {
try {
CompilerContext cc = (CompilerContext) QueryTreeNode.getContext(CompilerContext.CONTEXT_ID);
ClassFactory classFactory = cc.getClassFactory();
TypeCompilerFactory tcf = cc.getTypeCompilerFactory();
Class<?> derbyAggregatorInterface = classFactory.loadApplicationClass("org.apache.derby.agg.Aggregator");
Class<?> userAggregatorClass = classFactory.loadApplicationClass(_alias.getJavaClassName());
Class[][] typeBounds = classFactory.getClassInspector().getTypeBounds(derbyAggregatorInterface, userAggregatorClass);
if ((typeBounds == null) || (typeBounds.length != AGGREGATOR_PARAM_COUNT) || (typeBounds[INPUT_TYPE] == null) || (typeBounds[RETURN_TYPE] == null)) {
throw StandardException.newException(SQLState.LANG_ILLEGAL_UDA_CLASS, _alias.getSchemaName(), _alias.getName(), userAggregatorClass.getName());
}
Class<?>[] genericParameterTypes = classFactory.getClassInspector().getGenericParameterTypes(derbyAggregatorInterface, userAggregatorClass);
if (genericParameterTypes == null) {
genericParameterTypes = new Class<?>[AGGREGATOR_PARAM_COUNT];
}
AggregateAliasInfo aai = (AggregateAliasInfo) _alias.getAliasInfo();
DataTypeDescriptor expectedInputType = DataTypeDescriptor.getType(aai.getForType());
DataTypeDescriptor expectedReturnType = DataTypeDescriptor.getType(aai.getReturnType());
Class<?> expectedInputClass = getJavaClass(classFactory, expectedInputType);
Class<?> expectedReturnClass = getJavaClass(classFactory, expectedReturnType);
// the input operand must be coercible to the expected input type of the aggregate
if (!tcf.getTypeCompiler(expectedInputType.getTypeId()).storable(inputType.getTypeId(), classFactory)) {
return null;
}
//
// Make sure that the declared input type of the UDA actually falls within
// the type bounds of the Aggregator implementation.
//
Class[] inputBounds = typeBounds[INPUT_TYPE];
for (int i = 0; i < inputBounds.length; i++) {
vetCompatibility((Class<?>) inputBounds[i], expectedInputClass, SQLState.LANG_UDA_WRONG_INPUT_TYPE);
}
if (genericParameterTypes[INPUT_TYPE] != null) {
vetCompatibility(genericParameterTypes[INPUT_TYPE], expectedInputClass, SQLState.LANG_UDA_WRONG_INPUT_TYPE);
}
//
// Make sure that the declared return type of the UDA actually falls within
// the type bounds of the Aggregator implementation.
//
Class[] returnBounds = typeBounds[RETURN_TYPE];
for (int i = 0; i < returnBounds.length; i++) {
vetCompatibility(returnBounds[i], expectedReturnClass, SQLState.LANG_UDA_WRONG_RETURN_TYPE);
}
if (genericParameterTypes[RETURN_TYPE] != null) {
vetCompatibility(genericParameterTypes[RETURN_TYPE], expectedReturnClass, SQLState.LANG_UDA_WRONG_RETURN_TYPE);
}
aggregatorClass.append(ClassName.UserDefinedAggregator);
return expectedReturnType;
} catch (ClassNotFoundException cnfe) {
throw aggregatorInstantiation(cnfe);
}
}
use of org.apache.derby.iapi.sql.compile.CompilerContext in project derby by apache.
the class WindowFunctionNode method replaceCallsWithColumnReferences.
/**
* Replace window function calls in the expression tree with a
* ColumnReference to that window function, append the aggregate to the
* supplied RCL (assumed to be from the child ResultSetNode) and return the
* ColumnReference.
*
* @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 replaceCallsWithColumnReferences(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 a call to
// a window function
generatedRef.markGeneratedToReplaceWindowFunctionCall();
} else {
rcl.addResultColumn(generatedRC);
}
return generatedRef;
}
Aggregations