Search in sources :

Example 26 with MethodBuilder

use of org.apache.derby.iapi.services.compiler.MethodBuilder in project derby by apache.

the class ProjectRestrictNode method generateMinion.

/**
 * Logic shared by generate() and generateResultSet().
 *
 * @param acb	The ExpressionClassBuilder for the class being built
 * @param mb	The method the expression will go into
 *
 * @exception StandardException		Thrown on error
 */
private void generateMinion(ExpressionClassBuilder acb, MethodBuilder mb, boolean genChildResultSet) throws StandardException {
    /* If this ProjectRestrict doesn't do anything, bypass its generation.
		 * (Remove any true and true predicates first, as they could be left
		 * by the like transformation.)
		 */
    if (restrictionList != null && restrictionList.size() > 0) {
        restrictionList.eliminateBooleanTrueAndBooleanTrue();
    }
    if (nopProjectRestrict()) {
        generateNOPProjectRestrict();
        if (genChildResultSet)
            childResult.generateResultSet(acb, mb);
        else
            childResult.generate((ActivationClassBuilder) acb, mb);
        setCostEstimate(childResult.getFinalCostEstimate());
        return;
    }
    /* Put the predicates back into the tree */
    if (restrictionList != null) {
        constantRestriction = restrictionList.restoreConstantPredicates();
        // Remove any redundant predicates before restoring
        restrictionList.removeRedundantPredicates();
        restriction = restrictionList.restorePredicates();
        /* Allow the restrictionList to get garbage collected now
			 * that we're done with it.
			 */
        restrictionList = null;
    }
    // for the restriction, we generate an exprFun
    // that evaluates the expression of the clause
    // against the current row of the child's result.
    // if the restriction is empty, simply pass null
    // to optimize for run time performance.
    // generate the function and initializer:
    // Note: Boolean lets us return nulls (boolean would not)
    // private Boolean exprN()
    // {
    // return <<restriction.generate(ps)>>;
    // }
    // static Method exprN = method pointer to exprN;
    // Map the result columns to the source columns
    ResultColumnList.ColumnMapping mappingArrays = getResultColumns().mapSourceColumns();
    int[] mapArray = mappingArrays.mapArray;
    boolean[] cloneMap = mappingArrays.cloneMap;
    int mapArrayItem = acb.addItem(new ReferencedColumnsDescriptorImpl(mapArray));
    int cloneMapItem = acb.addItem(cloneMap);
    /* Will this node do a projection? */
    boolean doesProjection = true;
    /* Does a projection unless same # of columns in same order
		 * as child.
		 */
    if ((!reflectionNeededForProjection()) && mapArray != null && mapArray.length == childResult.getResultColumns().size()) {
        /* mapArray entries are 1-based */
        int index = 0;
        for (; index < mapArray.length; index++) {
            if (mapArray[index] != index + 1) {
                break;
            }
        }
        if (index == mapArray.length) {
            doesProjection = false;
        }
    }
    /* Generate the ProjectRestrictSet:
		 *	arg1: childExpress - Expression for childResultSet
		 *  arg2: Activation
		 *  arg3: restrictExpress - Expression for restriction
		 *  arg4: projectExpress - Expression for projection
		 *  arg5: resultSetNumber
		 *  arg6: constantExpress - Expression for constant restriction
		 *			(for example, where 1 = 2)
		 *  arg7: mapArrayItem - item # for mapping of source columns
         *  arg8: cloneMapItem - item # for mapping of columns that need cloning
         *  arg9: reuseResult - whether or not the result row can be reused
         *                      (ie, will it always be the same)
         *  arg10: doesProjection - does this node do a projection
         *  arg11: estimated row count
         *  arg12: estimated cost
         *  arg13: close method
         */
    acb.pushGetResultSetFactoryExpression(mb);
    if (genChildResultSet)
        childResult.generateResultSet(acb, mb);
    else
        childResult.generate((ActivationClassBuilder) acb, mb);
    /* Get the next ResultSet #, so that we can number this ResultSetNode, its
		 * ResultColumnList and ResultSet.
		 */
    assignResultSetNumber();
    /* Set the point of attachment in all subqueries attached
		 * to this node.
		 */
    if (projectSubquerys != null && projectSubquerys.size() > 0) {
        projectSubquerys.setPointOfAttachment(getResultSetNumber());
    }
    if (restrictSubquerys != null && restrictSubquerys.size() > 0) {
        restrictSubquerys.setPointOfAttachment(getResultSetNumber());
    }
    // Load our final cost estimate.
    setCostEstimate(getFinalCostEstimate());
    // if there is no restriction, we just want to pass null.
    if (restriction == null) {
        mb.pushNull(ClassName.GeneratedMethod);
    } else {
        // this sets up the method and the static field.
        // generates:
        // Object userExprFun { }
        MethodBuilder userExprFun = acb.newUserExprFun();
        // restriction knows it is returning its value;
        /* generates:
			 *    return  <restriction.generate(acb)>;
			 * and adds it to userExprFun
			 * NOTE: The explicit cast to DataValueDescriptor is required
			 * since the restriction may simply be a boolean column or subquery
			 * which returns a boolean.  For example:
			 *		where booleanColumn
			 */
        restriction.generateExpression(acb, userExprFun);
        userExprFun.methodReturn();
        // we are done modifying userExprFun, complete it.
        userExprFun.complete();
        // restriction is used in the final result set as an access of the new static
        // field holding a reference to this new method.
        // generates:
        // ActivationClass.userExprFun
        // which is the static field that "points" to the userExprFun
        // that evaluates the where clause.
        acb.pushMethodReference(mb, userExprFun);
    }
    /* Determine whether or not reflection is needed for the projection.
		 * Reflection is not needed if all of the columns map directly to source
		 * columns.
		 */
    if (reflectionNeededForProjection()) {
        // for the resultColumns, we generate a userExprFun
        // that creates a new row from expressions against
        // the current row of the child's result.
        // (Generate optimization: see if we can simply
        // return the current row -- we could, but don't, optimize
        // the function call out and have execution understand
        // that a null function pointer means take the current row
        // as-is, with the performance trade-off as discussed above.)
        /* Generate the Row function for the projection */
        getResultColumns().generateCore(acb, mb, false);
    } else {
        mb.pushNull(ClassName.GeneratedMethod);
    }
    mb.push(getResultSetNumber());
    // if there is no constant restriction, we just want to pass null.
    if (constantRestriction == null) {
        mb.pushNull(ClassName.GeneratedMethod);
    } else {
        // this sets up the method and the static field.
        // generates:
        // userExprFun { }
        MethodBuilder userExprFun = acb.newUserExprFun();
        // restriction knows it is returning its value;
        /* generates:
			 *    return <restriction.generate(acb)>;
			 * and adds it to userExprFun
			 * NOTE: The explicit cast to DataValueDescriptor is required
			 * since the restriction may simply be a boolean column or subquery
			 * which returns a boolean.  For example:
			 *		where booleanColumn
			 */
        constantRestriction.generateExpression(acb, userExprFun);
        userExprFun.methodReturn();
        // we are done modifying userExprFun, complete it.
        userExprFun.complete();
        // restriction is used in the final result set as an access
        // of the new static field holding a reference to this new method.
        // generates:
        // ActivationClass.userExprFun
        // which is the static field that "points" to the userExprFun
        // that evaluates the where clause.
        acb.pushMethodReference(mb, userExprFun);
    }
    mb.push(mapArrayItem);
    mb.push(cloneMapItem);
    mb.push(getResultColumns().reusableResult());
    mb.push(doesProjection);
    mb.push(validatingCheckConstraints);
    if (validatingBaseTableUUIDString == null) {
        mb.push(UUID.NULL);
    } else {
        mb.push(validatingBaseTableUUIDString);
    }
    mb.push(getCostEstimate().rowCount());
    mb.push(getCostEstimate().getEstimatedCost());
    mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getProjectRestrictResultSet", ClassName.NoPutResultSet, 13);
}
Also used : ReferencedColumnsDescriptorImpl(org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl) MethodBuilder(org.apache.derby.iapi.services.compiler.MethodBuilder)

Example 27 with MethodBuilder

use of org.apache.derby.iapi.services.compiler.MethodBuilder in project derby by apache.

the class StaticMethodCallNode method generateExpression.

/**
 * Do code generation for this method call
 *
 * @param acb	The ExpressionClassBuilder for the class we're generating
 * @param mb	The method the expression will go into
 *
 * @exception StandardException		Thrown on error
 */
void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
    if (routineInfo != null) {
        if (!routineInfo.calledOnNullInput() && routineInfo.getParameterCount() != 0)
            returnsNullOnNullState = acb.newFieldDeclaration(Modifier.PRIVATE, "boolean");
    }
    // reset the parameters are null indicator.
    if (returnsNullOnNullState != null) {
        mb.push(false);
        mb.setField(returnsNullOnNullState);
        // for the call to the generated method below.
        mb.pushThis();
    }
    int nargs = generateParameters(acb, mb);
    LocalField functionEntrySQLAllowed = null;
    if (routineInfo != null) {
        short sqlAllowed = routineInfo.getSQLAllowed();
        if (sqlAllowed != RoutineAliasInfo.NO_SQL) {
            int sqlOperation;
            if (sqlAllowed == RoutineAliasInfo.READS_SQL_DATA)
                sqlOperation = Authorizer.SQL_SELECT_OP;
            else if (sqlAllowed == RoutineAliasInfo.MODIFIES_SQL_DATA)
                sqlOperation = Authorizer.SQL_WRITE_OP;
            else
                sqlOperation = Authorizer.SQL_ARBITARY_OP;
            generateAuthorizeCheck((ActivationClassBuilder) acb, mb, sqlOperation);
        }
        int statmentContextReferences = isSystemCode ? 2 : 1;
        boolean isFunction = routineInfo.getReturnType() != null;
        if (isFunction)
            statmentContextReferences++;
        if (statmentContextReferences != 0) {
            acb.pushThisAsActivation(mb);
            mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);
            mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getStatementContext", "org.apache.derby.iapi.sql.conn.StatementContext", 0);
            for (int scc = 1; scc < statmentContextReferences; scc++) mb.dup();
        }
        /**
         *				Set the statement context to reflect we are running
         *				System procedures, so that we can execute non-standard SQL.
         */
        if (isSystemCode) {
            mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "setSystemCode", "void", 0);
        }
        // context.
        if (sqlAllowed != RoutineAliasInfo.NO_SQL) {
            generatePushNestedSessionContext((ActivationClassBuilder) acb, mb, routineInfo.hasDefinersRights(), routineDefiner);
        }
        // 
        if (isFunction) {
            functionEntrySQLAllowed = acb.newFieldDeclaration(Modifier.PRIVATE, "short");
            mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getSQLAllowed", "short", 0);
            mb.setField(functionEntrySQLAllowed);
        }
        // Set up the statement context to reflect the
        // restricted SQL execution allowed by this routine.
        mb.push(sqlAllowed);
        mb.push(false);
        mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "setSQLAllowed", "void", 2);
    }
    // a routine may make use of both varargs and dynamic ResultSets.
    if (routineInfo != null && !hasVarargs()) {
        int compiledResultSets = methodParameterTypes.length - methodParms.length;
        if (compiledResultSets != 0) {
            // Add a method that indicates the maxium number of dynamic result sets.
            int maxDynamicResults = routineInfo.getMaxDynamicResultSets();
            if (maxDynamicResults > 0) {
                MethodBuilder gdr = acb.getClassBuilder().newMethodBuilder(Modifier.PUBLIC, "int", "getMaxDynamicResults");
                gdr.push(maxDynamicResults);
                gdr.methodReturn();
                gdr.complete();
            }
            // add a method to return all the dynamic result sets (unordered)
            MethodBuilder gdr = acb.getClassBuilder().newMethodBuilder(Modifier.PUBLIC, "java.sql.ResultSet[][]", "getDynamicResults");
            MethodBuilder cons = acb.getConstructor();
            // if (procDef.getParameterStyle() == RoutineAliasInfo.PS_JAVA)
            {
                // PARAMETER STYLE JAVA
                LocalField procedureResultSetsHolder = acb.newFieldDeclaration(Modifier.PRIVATE, "java.sql.ResultSet[][]");
                // getDynamicResults body
                gdr.getField(procedureResultSetsHolder);
                // create the holder of all the ResultSet arrays, new java.sql.ResultSet[][compiledResultSets]
                cons.pushNewArray("java.sql.ResultSet[]", compiledResultSets);
                cons.setField(procedureResultSetsHolder);
                // arguments for the dynamic result sets
                for (int i = 0; i < compiledResultSets; i++) {
                    mb.pushNewArray("java.sql.ResultSet", 1);
                    mb.dup();
                    mb.getField(procedureResultSetsHolder);
                    mb.swap();
                    mb.setArrayElement(i);
                }
            }
            // complete the method that returns the ResultSet[][] to the
            gdr.methodReturn();
            gdr.complete();
            nargs += compiledResultSets;
        }
    }
    String javaReturnType = getJavaTypeName();
    MethodBuilder mbnc = null;
    MethodBuilder mbcm = mb;
    // do not call the method, just return null.
    if (returnsNullOnNullState != null) {
        mbnc = acb.newGeneratedFun(javaReturnType, Modifier.PRIVATE, methodParameterTypes);
        // add the throws clause for the public static method we are going to call.
        Class[] throwsSet = ((java.lang.reflect.Method) method).getExceptionTypes();
        for (int te = 0; te < throwsSet.length; te++) {
            mbnc.addThrownException(throwsSet[te].getName());
        }
        mbnc.getField(returnsNullOnNullState);
        mbnc.conditionalIf();
        // set up for a null!!
        // for objects is easy.
        mbnc.pushNull(javaReturnType);
        mbnc.startElseCode();
        if (!actualMethodReturnType.equals(javaReturnType))
            mbnc.pushNewStart(javaReturnType);
        // fetch all the arguments
        for (int pa = 0; pa < nargs; pa++) {
            mbnc.getParameter(pa);
        }
        mbcm = mbnc;
    }
    mbcm.callMethod(VMOpcode.INVOKESTATIC, method.getDeclaringClass().getName(), methodName, actualMethodReturnType, nargs);
    if (returnsNullOnNullState != null) {
        // compatible with their function return types.
        if (!actualMethodReturnType.equals(javaReturnType)) {
            if (actualMethodReturnType.equals("short") && javaReturnType.equals("java.lang.Integer"))
                mbnc.upCast("int");
            mbnc.pushNewComplete(1);
        }
        mbnc.completeConditional();
        mbnc.methodReturn();
        mbnc.complete();
        // now call the wrapper method
        mb.callMethod(VMOpcode.INVOKEVIRTUAL, acb.getClassBuilder().getFullName(), mbnc.getName(), javaReturnType, nargs);
        mbnc = null;
    }
    if (routineInfo != null) {
        // entry to the method.
        if (functionEntrySQLAllowed != null) {
            acb.pushThisAsActivation(mb);
            mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);
            mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getStatementContext", "org.apache.derby.iapi.sql.conn.StatementContext", 0);
            mb.getField(functionEntrySQLAllowed);
            // override as we are ending the control set by this function all.
            mb.push(true);
            mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "setSQLAllowed", "void", 2);
        }
        if (outParamArrays != null) {
            MethodBuilder constructor = acb.getConstructor();
            // constructor  - setting up correct parameter type info
            acb.pushThisAsActivation(constructor);
            constructor.callMethod(VMOpcode.INVOKEINTERFACE, null, "getParameterValueSet", ClassName.ParameterValueSet, 0);
            // execute  - passing out parameters back.
            acb.pushThisAsActivation(mb);
            mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getParameterValueSet", ClassName.ParameterValueSet, 0);
            int[] parameterModes = routineInfo.getParameterModes();
            for (int i = 0; i < outParamArrays.length; i++) {
                int parameterMode = parameterModes[getRoutineArgIdx(i)];
                if (parameterMode != (ParameterMetaData.parameterModeIn)) {
                    // must be a parameter if it is INOUT or OUT.
                    ValueNode sqlParamNode = ((SQLToJavaValueNode) methodParms[i]).getSQLValueNode();
                    int applicationParameterNumber = applicationParameterNumbers[i];
                    // Set the correct parameter nodes in the ParameterValueSet at constructor time.
                    constructor.dup();
                    constructor.push(applicationParameterNumber);
                    constructor.push(parameterMode);
                    constructor.callMethod(VMOpcode.INVOKEINTERFACE, null, "setParameterMode", "void", 2);
                    // Pass the value of the outparameters back to the calling code
                    LocalField lf = outParamArrays[i];
                    mb.dup();
                    mb.push(applicationParameterNumber);
                    mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "getParameter", ClassName.DataValueDescriptor, 1);
                    // see if we need to set the desired length/scale/precision of the type
                    DataTypeDescriptor paramdtd = sqlParamNode.getTypeServices();
                    boolean isNumericType = paramdtd.getTypeId().isNumericTypeId();
                    boolean isAnsiUDT = paramdtd.getTypeId().getBaseTypeId().isAnsiUDT();
                    // is the underlying type for the OUT/INOUT parameter primitive.
                    // if this is a varargs arg then we have to strip off another array level
                    Class<?> cellType = ((Method) method).getParameterTypes()[getRoutineArgIdx(i)].getComponentType();
                    if (isVararg(i)) {
                        cellType = cellType.getComponentType();
                    }
                    boolean isPrimitive = cellType.isPrimitive();
                    if (isNumericType) {
                        if (!isPrimitive)
                            mb.cast(ClassName.NumberDataValue);
                    } else if (paramdtd.getTypeId().isBooleanTypeId()) {
                        // need to cast as the setValue(Boolean) method only exists on BooleanDataValue
                        if (!isPrimitive)
                            mb.cast(ClassName.BooleanDataValue);
                    }
                    if (paramdtd.getTypeId().variableLength()) {
                        // need another DVD reference for the set width below.
                        mb.dup();
                    }
                    // pvs, dvd, array
                    mb.getField(lf);
                    // pvs, dvd, value
                    mb.getArrayElement(0);
                    // The value needs to be set thorugh the setValue(Number) method.
                    if (isNumericType && !isPrimitive) {
                        mb.upCast("java.lang.Number");
                    }
                    // The value needs to be set thorugh the setValue(Object) method.
                    if (isAnsiUDT) {
                        mb.upCast("java.lang.Object");
                    }
                    mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "setValue", "void", 1);
                    if (paramdtd.getTypeId().variableLength()) {
                        mb.push(isNumericType ? paramdtd.getPrecision() : paramdtd.getMaximumWidth());
                        mb.push(paramdtd.getScale());
                        mb.push(isNumericType);
                        mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue, "setWidth", "void", 3);
                    // mb.endStatement();
                    }
                }
            }
            constructor.endStatement();
            mb.endStatement();
        }
    }
}
Also used : DataTypeDescriptor(org.apache.derby.iapi.types.DataTypeDescriptor) Method(java.lang.reflect.Method) LocalField(org.apache.derby.iapi.services.compiler.LocalField) MethodBuilder(org.apache.derby.iapi.services.compiler.MethodBuilder)

Example 28 with MethodBuilder

use of org.apache.derby.iapi.services.compiler.MethodBuilder in project derby by apache.

the class StaticMethodCallNode method generateOneParameter.

/**
 *		Push extra code to generate the casts within the
 *		arrays for the parameters passed as arrays.
 */
@Override
void generateOneParameter(ExpressionClassBuilder acb, MethodBuilder mb, int parameterNumber) throws StandardException {
    int parameterMode;
    SQLToJavaValueNode sql2j = null;
    if (methodParms[parameterNumber] instanceof SQLToJavaValueNode)
        sql2j = (SQLToJavaValueNode) methodParms[parameterNumber];
    if (routineInfo != null) {
        parameterMode = routineInfo.getParameterModes()[getRoutineArgIdx(parameterNumber)];
    } else {
        // for a static method call the parameter always starts out as a in parameter, but
        // may be registered as an IN OUT parameter. For a static method argument to be
        // a dynmaically registered out parameter it must be a simple ? parameter
        parameterMode = (ParameterMetaData.parameterModeIn);
        if (sql2j != null) {
            if (sql2j.getSQLValueNode().requiresTypeFromContext()) {
                ParameterNode pn;
                if (sql2j.getSQLValueNode() instanceof UnaryOperatorNode)
                    pn = ((UnaryOperatorNode) sql2j.getSQLValueNode()).getParameterOperand();
                else
                    pn = (ParameterNode) (sql2j.getSQLValueNode());
                // applicationParameterNumbers is only set up for a procedure.
                int applicationParameterNumber = pn.getParameterNumber();
                String parameterType = methodParameterTypes[getRoutineArgIdx(parameterNumber)];
                if (parameterType.endsWith("[]")) {
                    // constructor  - setting up correct parameter type info
                    MethodBuilder constructor = acb.getConstructor();
                    acb.pushThisAsActivation(constructor);
                    constructor.callMethod(VMOpcode.INVOKEINTERFACE, null, "getParameterValueSet", ClassName.ParameterValueSet, 0);
                    constructor.push(applicationParameterNumber);
                    constructor.push(ParameterMetaData.parameterModeUnknown);
                    constructor.callMethod(VMOpcode.INVOKEINTERFACE, null, "setParameterMode", "void", 2);
                    constructor.endStatement();
                }
            }
        }
    }
    switch(parameterMode) {
        case (ParameterMetaData.parameterModeIn):
        case (ParameterMetaData.parameterModeInOut):
        case (ParameterMetaData.parameterModeUnknown):
            if (sql2j != null)
                sql2j.returnsNullOnNullState = returnsNullOnNullState;
            super.generateOneParameter(acb, mb, parameterNumber);
            break;
        case (ParameterMetaData.parameterModeOut):
            // method call from the parameter node.
            break;
    }
    switch(parameterMode) {
        case (ParameterMetaData.parameterModeIn):
        case (ParameterMetaData.parameterModeUnknown):
            break;
        case (ParameterMetaData.parameterModeInOut):
        case (ParameterMetaData.parameterModeOut):
            {
                // Create the array used to pass into the method. We create a
                // new array for each call as there is a small chance the
                // application could retain a reference to it and corrupt
                // future calls with the same CallableStatement object.
                String methodParameterType = methodParameterTypes[getRoutineArgIdx(parameterNumber)];
                String arrayType = methodParameterType.substring(0, methodParameterType.length() - 2);
                // if a varargs arg, then strip off the extra array dimension added by varargs
                if (isVararg(parameterNumber)) {
                    methodParameterType = stripOneArrayLevel(methodParameterType);
                    arrayType = stripOneArrayLevel(arrayType);
                }
                LocalField lf = acb.newFieldDeclaration(Modifier.PRIVATE, methodParameterType);
                if (outParamArrays == null) {
                    outParamArrays = new LocalField[methodParms.length];
                }
                outParamArrays[parameterNumber] = lf;
                mb.pushNewArray(arrayType, 1);
                mb.putField(lf);
                // set the IN part of the parameter into the INOUT parameter.
                if (parameterMode != (ParameterMetaData.parameterModeOut)) {
                    mb.swap();
                    mb.setArrayElement(0);
                    mb.getField(lf);
                }
                break;
            }
    }
}
Also used : MethodBuilder(org.apache.derby.iapi.services.compiler.MethodBuilder) LocalField(org.apache.derby.iapi.services.compiler.LocalField)

Example 29 with MethodBuilder

use of org.apache.derby.iapi.services.compiler.MethodBuilder in project derby by apache.

the class SubqueryNode method generateExpression.

/**
 * Do code generation for this subquery.
 *
 * @param expressionBuilder	The ExpressionClassBuilder for the class being built
 * @param mbex	The method the expression will go into
 *
 * @exception StandardException		Thrown on error
 */
@Override
void generateExpression(ExpressionClassBuilder expressionBuilder, MethodBuilder mbex) throws StandardException {
    CompilerContext cc = getCompilerContext();
    String resultSetString;
    if (SanityManager.DEBUG) {
        SanityManager.ASSERT(expressionBuilder instanceof ActivationClassBuilder, "Expecting an ActivationClassBuilder");
    }
    ActivationClassBuilder acb = (ActivationClassBuilder) expressionBuilder;
    /* Generate the appropriate (Any or Once) ResultSet */
    if (subqueryType == EXPRESSION_SUBQUERY) {
        resultSetString = "getOnceResultSet";
    } else {
        resultSetString = "getAnyResultSet";
    }
    // Get cost estimate for underlying subquery
    CostEstimate costEstimate = resultSet.getFinalCostEstimate();
    /* Generate a new method.  It's only used within the other
		 * exprFuns, so it could be private. but since we don't
		 * generate the right bytecodes to invoke private methods,
		 * we just make it protected.  This generated class won't
		 * have any subclasses, certainly! (nat 12/97)
		 */
    String subqueryTypeString = getTypeCompiler().interfaceName();
    MethodBuilder mb = acb.newGeneratedFun(subqueryTypeString, Modifier.PROTECTED);
    /* Declare the field to hold the suquery's ResultSet tree */
    LocalField rsFieldLF = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.NoPutResultSet);
    ResultSetNode subNode = null;
    if (!isMaterializable()) {
        MethodBuilder executeMB = acb.getExecuteMethod();
        if (pushedNewPredicate && (!hasCorrelatedCRs())) {
            /* We try to materialize the subquery if it can fit in the memory.  We
				 * evaluate the subquery first.  If the result set fits in the memory,
				 * we replace the resultset with in-memory unions of row result sets.
				 * We do this trick by replacing the child result with a new node --
				 * MaterializeSubqueryNode, which essentially generates the suitable
				 * code to materialize the subquery if possible.  This may have big
				 * performance improvement.  See beetle 4373.
				 */
            if (SanityManager.DEBUG) {
                SanityManager.ASSERT(resultSet instanceof ProjectRestrictNode, "resultSet expected to be a ProjectRestrictNode!");
            }
            subNode = ((ProjectRestrictNode) resultSet).getChildResult();
            LocalField subRS = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.NoPutResultSet);
            mb.getField(subRS);
            mb.conditionalIfNull();
            ResultSetNode materialSubNode = new MaterializeSubqueryNode(subRS, getContextManager());
            // Propagate the resultSet's cost estimate to the new node.
            materialSubNode.setCostEstimate(resultSet.getFinalCostEstimate());
            ((ProjectRestrictNode) resultSet).setChildResult(materialSubNode);
            /* Evaluate subquery resultset here first.  Next time when we come to
				 * this subquery it may be replaced by a bunch of unions of rows.
				 */
            subNode.generate(acb, mb);
            mb.startElseCode();
            mb.getField(subRS);
            mb.completeConditional();
            mb.setField(subRS);
            executeMB.pushNull(ClassName.NoPutResultSet);
            executeMB.setField(subRS);
        }
        executeMB.pushNull(ClassName.NoPutResultSet);
        executeMB.setField(rsFieldLF);
        // now we fill in the body of the conditional
        mb.getField(rsFieldLF);
        mb.conditionalIfNull();
    }
    acb.pushGetResultSetFactoryExpression(mb);
    // start of args
    int nargs;
    /* Inside here is where subquery could already have been materialized. 4373
		 */
    resultSet.generate(acb, mb);
    /* Get the next ResultSet #, so that we can number the subquery's 
		 * empty row ResultColumnList and Once/Any ResultSet.
		 */
    int subqResultSetNumber = cc.getNextResultSetNumber();
    /* We will be reusing the RCL from the subquery's ResultSet for the 
		 * empty row function.  We need to reset the resultSetNumber in the
		 * RCL, before we generate that function.  Now that we've called
		 * generate() on the subquery's ResultSet, we can reset that
		 * resultSetNumber.
		 */
    resultSet.getResultColumns().setResultSetNumber(subqResultSetNumber);
    /* Generate code for empty row */
    resultSet.getResultColumns().generateNulls(acb, mb);
    /*
		 *	arg1: suqueryExpress - Expression for subquery's
		 *		  ResultSet
		 *  arg2: Activation
		 *  arg3: Method to generate Row with null(s) if subquery
		 *		  Result Set is empty
		 */
    if (subqueryType == EXPRESSION_SUBQUERY) {
        int cardinalityCheck;
        /* No need to do sort if subquery began life as a distinct expression subquery.
			 * (We simply check for a single unique value at execution time.)
			 * No need for cardinality check if we know that underlying
			 * ResultSet can contain at most 1 row.
			 * RESOLVE - Not necessary if we know we
			 * are getting a single row because of a unique index.
			 */
        if (distinctExpression) {
            cardinalityCheck = OnceResultSet.UNIQUE_CARDINALITY_CHECK;
        } else if (resultSet.returnsAtMostOneRow()) {
            cardinalityCheck = OnceResultSet.NO_CARDINALITY_CHECK;
        } else {
            cardinalityCheck = OnceResultSet.DO_CARDINALITY_CHECK;
        }
        /*  arg4: int - whether or not cardinality check is required
			 *				DO_CARDINALITY_CHECK - required
			 *				NO_CARDINALITY_CHECK - not required
			 *				UNIQUE_CARDINALITY_CHECK - verify single
			 *											unique value
			 */
        mb.push(cardinalityCheck);
        nargs = 8;
    } else {
        nargs = 7;
    }
    mb.push(subqResultSetNumber);
    mb.push(subqueryNumber);
    mb.push(pointOfAttachment);
    mb.push(costEstimate.rowCount());
    mb.push(costEstimate.getEstimatedCost());
    mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, resultSetString, ClassName.NoPutResultSet, nargs);
    if (!isMaterializable()) {
        /* put it back
			 */
        if (pushedNewPredicate && (!hasCorrelatedCRs()))
            ((ProjectRestrictNode) resultSet).setChildResult(subNode);
        // now we fill in the body of the conditional
        mb.startElseCode();
        mb.getField(rsFieldLF);
        mb.completeConditional();
    }
    mb.setField(rsFieldLF);
    /* rs.openCore() */
    mb.getField(rsFieldLF);
    mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "openCore", "void", 0);
    /* r = rs.next() */
    mb.getField(rsFieldLF);
    mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getNextRowCore", ClassName.ExecRow, 0);
    // mb.putVariable(rVar);
    // mb.endStatement();
    /* col = (<Datatype interface>) r.getColumn(1) */
    // mb.getVariable(rVar);
    // both the Row interface and columnId are 1-based
    mb.push(1);
    mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "getColumn", ClassName.DataValueDescriptor, 1);
    mb.cast(subqueryTypeString);
    /* Only generate the close() method for materialized
		 * subqueries.  All others will be closed when the
		 * close() method is called on the top ResultSet.
		 */
    if (isMaterializable()) {
        /* rs.close() */
        mb.getField(rsFieldLF);
        mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.ResultSet, "close", "void", 0);
    }
    /* return col */
    // mb.getVariable(colVar);
    mb.methodReturn();
    mb.complete();
    /*
		** If we have an expression subquery, then we
		** can materialize it if it has no correlated
		** column references and is invariant.
		*/
    if (isMaterializable()) {
        LocalField lf = generateMaterialization(acb, mb, subqueryTypeString);
        mbex.getField(lf);
    } else {
        /* Generate the call to the new method */
        mbex.pushThis();
        mbex.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, mb.getName(), subqueryTypeString, 0);
    }
}
Also used : CompilerContext(org.apache.derby.iapi.sql.compile.CompilerContext) CostEstimate(org.apache.derby.iapi.sql.compile.CostEstimate) MethodBuilder(org.apache.derby.iapi.services.compiler.MethodBuilder) LocalField(org.apache.derby.iapi.services.compiler.LocalField)

Example 30 with MethodBuilder

use of org.apache.derby.iapi.services.compiler.MethodBuilder in project derby by apache.

the class UnaryComparisonOperatorNode method generateQualMethod.

/**
 * @see RelationalOperator#generateQualMethod
 *
 * @exception StandardException		Thrown on error
 */
public void generateQualMethod(ExpressionClassBuilderInterface acbi, MethodBuilder mb, Optimizable optTable) throws StandardException {
    ExpressionClassBuilder acb = (ExpressionClassBuilder) acbi;
    MethodBuilder qualMethod = acb.newUserExprFun();
    /* Generate a method that returns that expression */
    acb.generateNull(qualMethod, operand.getTypeCompiler(), operand.getTypeServices().getCollationType());
    qualMethod.methodReturn();
    qualMethod.complete();
    /* Return an expression that evaluates to the GeneratedMethod */
    acb.pushMethodReference(mb, qualMethod);
}
Also used : MethodBuilder(org.apache.derby.iapi.services.compiler.MethodBuilder)

Aggregations

MethodBuilder (org.apache.derby.iapi.services.compiler.MethodBuilder)48 LocalField (org.apache.derby.iapi.services.compiler.LocalField)18 ReferencedColumnsDescriptorImpl (org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl)3 OptimizablePredicate (org.apache.derby.iapi.sql.compile.OptimizablePredicate)3 Method (java.lang.reflect.Method)1 ArrayList (java.util.ArrayList)1 FormatableArrayHolder (org.apache.derby.iapi.services.io.FormatableArrayHolder)1 FormatableIntHolder (org.apache.derby.iapi.services.io.FormatableIntHolder)1 GeneratedClass (org.apache.derby.iapi.services.loader.GeneratedClass)1 CompilerContext (org.apache.derby.iapi.sql.compile.CompilerContext)1 CostEstimate (org.apache.derby.iapi.sql.compile.CostEstimate)1 StaticCompiledOpenConglomInfo (org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo)1 DataTypeDescriptor (org.apache.derby.iapi.types.DataTypeDescriptor)1 SqlXmlUtil (org.apache.derby.iapi.types.SqlXmlUtil)1 StandardException (org.apache.derby.shared.common.error.StandardException)1