Search in sources :

Example 31 with CompilerContext

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();
    }
}
Also used : TypeId(org.apache.derby.iapi.types.TypeId) ProviderList(org.apache.derby.iapi.sql.depend.ProviderList) DataTypeDescriptor(org.apache.derby.iapi.types.DataTypeDescriptor) CompilerContext(org.apache.derby.iapi.sql.compile.CompilerContext) ArrayList(java.util.ArrayList) DefaultInfoImpl(org.apache.derby.catalog.types.DefaultInfoImpl)

Example 32 with CompilerContext

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();
    }
}
Also used : CompilerContext(org.apache.derby.iapi.sql.compile.CompilerContext) ColumnDescriptor(org.apache.derby.iapi.sql.dictionary.ColumnDescriptor)

Example 33 with CompilerContext

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);
}
Also used : CompilerContext(org.apache.derby.iapi.sql.compile.CompilerContext) ArrayList(java.util.ArrayList)

Example 34 with CompilerContext

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);
    }
}
Also used : ClassFactory(org.apache.derby.iapi.services.loader.ClassFactory) TypeCompilerFactory(org.apache.derby.iapi.sql.compile.TypeCompilerFactory) DataTypeDescriptor(org.apache.derby.iapi.types.DataTypeDescriptor) CompilerContext(org.apache.derby.iapi.sql.compile.CompilerContext) AggregateAliasInfo(org.apache.derby.catalog.types.AggregateAliasInfo)

Example 35 with CompilerContext

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;
}
Also used : CompilerContext(org.apache.derby.iapi.sql.compile.CompilerContext)

Aggregations

CompilerContext (org.apache.derby.iapi.sql.compile.CompilerContext)53 SchemaDescriptor (org.apache.derby.iapi.sql.dictionary.SchemaDescriptor)12 DataDictionary (org.apache.derby.iapi.sql.dictionary.DataDictionary)10 DataTypeDescriptor (org.apache.derby.iapi.types.DataTypeDescriptor)9 Parser (org.apache.derby.iapi.sql.compile.Parser)8 Visitable (org.apache.derby.iapi.sql.compile.Visitable)6 TypeId (org.apache.derby.iapi.types.TypeId)6 LanguageConnectionContext (org.apache.derby.iapi.sql.conn.LanguageConnectionContext)5 ProviderList (org.apache.derby.iapi.sql.depend.ProviderList)5 ConglomerateDescriptor (org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor)5 ArrayList (java.util.ArrayList)4 ColumnDescriptor (org.apache.derby.iapi.sql.dictionary.ColumnDescriptor)4 TableDescriptor (org.apache.derby.iapi.sql.dictionary.TableDescriptor)4 ContextManager (org.apache.derby.iapi.services.context.ContextManager)3 StandardException (org.apache.derby.shared.common.error.StandardException)3 UUID (org.apache.derby.catalog.UUID)2 DefaultInfoImpl (org.apache.derby.catalog.types.DefaultInfoImpl)2 ClassFactory (org.apache.derby.iapi.services.loader.ClassFactory)2 CostEstimate (org.apache.derby.iapi.sql.compile.CostEstimate)2 TypeCompilerFactory (org.apache.derby.iapi.sql.compile.TypeCompilerFactory)2