Search in sources :

Example 21 with LocalField

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

the class SpecialFunctionNode method generateExpression.

/**
 *		Generate an expression that returns a DataValueDescriptor and
 *		calls a method off the language connection or the activation.
 *
 * @param acb	The ExpressionClassBuilder for the class being built
 * @param mb	The method the code to place the code
 *
 * @exception StandardException		Thrown on error
 */
@Override
void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
    mb.pushThis();
    mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Activation, "getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);
    int argCount = 0;
    if (methodName.equals("getCurrentRoleIdDelimited") || methodName.equals("getCurrentSchemaName") || methodName.equals("getCurrentUserId")) {
        acb.pushThisAsActivation(mb);
        argCount++;
    }
    mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, methodName, methodType, argCount);
    String fieldType = getTypeCompiler().interfaceName();
    LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, fieldType);
    acb.generateDataValue(mb, getTypeCompiler(), getTypeServices().getCollationType(), field);
}
Also used : LocalField(org.apache.derby.iapi.services.compiler.LocalField)

Example 22 with LocalField

use of org.apache.derby.iapi.services.compiler.LocalField 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 23 with LocalField

use of org.apache.derby.iapi.services.compiler.LocalField 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 24 with LocalField

use of org.apache.derby.iapi.services.compiler.LocalField 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 25 with LocalField

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

the class UserTypeConstantNode method generateExpression.

/**
 * For a UserTypeConstantNode, we have to store away the object somewhere
 * and have a way to get it back at runtime.
 * These objects are serializable.  This gives us at least two options:
 * 1) serialize it out into a byte array field, and serialize
 *	  it back in when needed, from the field.
 * 2) have an array of objects in the prepared statement and a #,
 *	  to find the object directly. Because it is serializable, it
 *	  will store with the rest of the executable just fine.
 * Choice 2 gives better performance -- the ser/deser cost is paid
 * on database access for the statement, not for each execution of it.
 * However, it requires some infrastructure support from prepared
 * statements.  For now, we take choice 3, and make some assumptions
 * about available methods on the user type.  This choice has the
 * shortcoming that it will not work for arbitrary user types.
 * REVISIT and implement choice 2 when a general solution is needed.
 * <p>
 * A null is generated as a Null value cast to the type of
 * the constant node.
 *
 * @param acb	The ExpressionClassBuilder for the class being built
 * @param mb	The method the expression will go into
 *
 * @exception StandardException		Thrown on error
 */
@Override
void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
    TypeCompiler tc = getTypeCompiler();
    String fieldType = tc.interfaceName();
    /* Are we generating a SQL null value? */
    if (val == null) {
        acb.generateNull(mb, tc, getTypeServices().getCollationType());
    } else // The code generated here is invoked when the generated class is constructed. However the prepared statement
    // is not set into the activation class when it is constructed, but later. So we cannot use the getSavedObject
    // method to retrieve the value.
    // else if( value instanceof DataValueDescriptor)
    // {
    // acb.pushThisAsActivation( mb);
    // mb.callMethod( VMOpcode.INVOKEINTERFACE,
    // null,
    // "getPreparedStatement",
    // ClassName.ExecPreparedStatement,
    // 0);
    // mb.push( acb.addItem( value));
    // mb.callMethod( VMOpcode.INVOKEINTERFACE,
    // null,
    // "getSavedObject",
    // "java.lang.Object",
    // 1);
    // mb.cast( fieldType);
    // }
    {
        /*
				The generated java is the expression:
					<java type name>.valueOf("<value.toString>")

				super.generateValue will wrap this expression in
				the appropriate column constructor.

				If the type doesn't have a valueOf method, then we will
				give an error.  We have to assume that valueOf will
				reconstruct the object from a String literal.  If this is
				a false assumption, some other object may be constructed,
				or a runtime error may result due to valueOf failing.
		 	*/
        String typeName = getTypeId().getCorrespondingJavaTypeName();
        mb.push(val.toString());
        mb.callMethod(VMOpcode.INVOKESTATIC, typeName, "valueOf", typeName, 1);
        LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, fieldType);
        acb.generateDataValue(mb, tc, getTypeServices().getCollationType(), field);
    }
}
Also used : TypeCompiler(org.apache.derby.iapi.sql.compile.TypeCompiler) LocalField(org.apache.derby.iapi.services.compiler.LocalField)

Aggregations

LocalField (org.apache.derby.iapi.services.compiler.LocalField)32 MethodBuilder (org.apache.derby.iapi.services.compiler.MethodBuilder)18 OptimizablePredicate (org.apache.derby.iapi.sql.compile.OptimizablePredicate)3 TypeCompiler (org.apache.derby.iapi.sql.compile.TypeCompiler)2 Method (java.lang.reflect.Method)1 ArrayList (java.util.ArrayList)1 CompilerContext (org.apache.derby.iapi.sql.compile.CompilerContext)1 CostEstimate (org.apache.derby.iapi.sql.compile.CostEstimate)1 DataTypeDescriptor (org.apache.derby.iapi.types.DataTypeDescriptor)1 SqlXmlUtil (org.apache.derby.iapi.types.SqlXmlUtil)1 TypeId (org.apache.derby.iapi.types.TypeId)1