Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / compile / StaticMethodCallNode.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
new file mode 100644 (file)
index 0000000..39a82ab
--- /dev/null
@@ -0,0 +1,1128 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.StaticMethodCallNode\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to you under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+package        org.apache.derby.impl.sql.compile;\r
+\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.sql.compile.CompilerContext;\r
+import org.apache.derby.iapi.sql.compile.TypeCompiler;\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+import org.apache.derby.iapi.types.JSQLType;\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.types.StringDataValue;\r
+import org.apache.derby.iapi.types.TypeId;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.AliasDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;\r
+\r
+import org.apache.derby.iapi.reference.ClassName;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.reference.JDBC30Translation;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;\r
+import org.apache.derby.iapi.services.loader.ClassInspector;\r
+import org.apache.derby.iapi.services.compiler.LocalField;\r
+\r
+import org.apache.derby.iapi.util.JBitSet;\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+\r
+import org.apache.derby.iapi.sql.conn.Authorizer;\r
+\r
+import org.apache.derby.catalog.AliasInfo;\r
+import org.apache.derby.catalog.TypeDescriptor;\r
+import org.apache.derby.catalog.types.RoutineAliasInfo;\r
+import org.apache.derby.impl.sql.compile.ActivationClassBuilder;\r
+\r
+import org.apache.derby.catalog.UUID;\r
+\r
+import java.util.Vector;\r
+import java.lang.reflect.Modifier;\r
+\r
+/**\r
+ * A StaticMethodCallNode represents a static method call from a Class\r
+ * (as opposed to from an Object).\r
+\r
+   For a procedure the call requires that the arguments be ? parameters.\r
+   The parameter is *logically* passed into the method call a number of different ways.\r
+\r
+   <P>\r
+   For a application call like CALL MYPROC(?) the logically Java method call is\r
+   (in psuedo Java/SQL code) (examples with CHAR(10) parameter)\r
+   <BR>\r
+   Fixed length IN parameters - com.acme.MyProcedureMethod(?)\r
+   <BR>\r
+   Variable length IN parameters - com.acme.MyProcedureMethod(CAST (? AS CHAR(10))\r
+   <BR>\r
+   Fixed length INOUT parameter -\r
+               String[] holder = new String[] {?}; com.acme.MyProcedureMethod(holder); ? = holder[0]\r
+   <BR>\r
+   Variable length INOUT parameter -\r
+               String[] holder = new String[] {CAST (? AS CHAR(10)}; com.acme.MyProcedureMethod(holder); ? = CAST (holder[0] AS CHAR(10))\r
+\r
+   <BR>\r
+   Fixed length OUT parameter -\r
+               String[] holder = new String[1]; com.acme.MyProcedureMethod(holder); ? = holder[0]\r
+\r
+   <BR>\r
+   Variable length INOUT parameter -\r
+               String[] holder = new String[1]; com.acme.MyProcedureMethod(holder); ? = CAST (holder[0] AS CHAR(10))\r
+\r
+\r
+    <P>\r
+       For static method calls there is no pre-definition of an IN or INOUT parameter, so a call to CallableStatement.registerOutParameter()\r
+       makes the parameter an INOUT parameter, provided:\r
+               - the parameter is passed directly to the method call (no casts or expressions).\r
+               - the method's parameter type is a Java array type.\r
+\r
+    Since this is a dynmaic decision we compile in code to take both paths, based upon a boolean isINOUT which is dervied from the\r
+       ParameterValueSet. Code is logically (only single parameter String[] shown here). Note, no casts can exist here.\r
+\r
+       boolean isINOUT = getParameterValueSet().getParameterMode(0) == PARAMETER_IN_OUT;\r
+       if (isINOUT) {\r
+               String[] holder = new String[] {?}; com.acme.MyProcedureMethod(holder); ? = holder[0]\r
+          \r
+       } else {\r
+               com.acme.MyProcedureMethod(?)\r
+       }\r
+\r
+ *\r
+ */\r
+public class StaticMethodCallNode extends MethodCallNode\r
+{\r
+       private TableName procedureName;\r
+\r
+       private LocalField[] outParamArrays;\r
+       private int[]            applicationParameterNumbers; \r
+\r
+       private boolean         isSystemCode;\r
+       private boolean         alreadyBound;\r
+\r
+    /**\r
+     * Generated boolean field to hold the indicator\r
+     * for if any of the parameters to a\r
+     * RETURNS NULL ON NULL INPUT function are NULL.\r
+     * Only set if this node is calling such a function.\r
+     * Set at generation time.\r
+     */\r
+       private LocalField      returnsNullOnNullState;\r
+\r
+\r
+       AliasDescriptor ad;\r
+\r
+\r
+       /**\r
+        * Intializer for a NonStaticMethodCallNode\r
+        *\r
+        * @param methodName            The name of the method to call\r
+        * @param javaClassName         The name of the java class that the static method belongs to.\r
+        */\r
+       public void init(Object methodName, Object javaClassName)\r
+       {\r
+               if (methodName instanceof String)\r
+                       init(methodName);\r
+               else {\r
+                       procedureName = (TableName) methodName;\r
+                       init(procedureName.getTableName());\r
+               }\r
+\r
+               this.javaClassName = (String) javaClassName;\r
+       }\r
+\r
+       /**\r
+        * Bind this expression.  This means binding the sub-expressions,\r
+        * as well as figuring out what the return type is for this expression.\r
+        *\r
+        * @param fromList              The FROM list for the query this\r
+        *                              expression is in, for binding columns.\r
+        * @param subqueryList          The subquery list being built as we find SubqueryNodes\r
+        * @param aggregateVector       The aggregate vector being built as we find AggregateNodes\r
+        *\r
+        * @return      this or an AggregateNode\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public JavaValueNode bindExpression(\r
+               FromList fromList, SubqueryList subqueryList,\r
+               Vector  aggregateVector) \r
+                       throws StandardException\r
+       {\r
+               // for a function we can get called recursively\r
+               if (alreadyBound)\r
+                       return this;\r
+\r
+\r
+               bindParameters(fromList, subqueryList, aggregateVector);\r
+\r
+               \r
+               /* If javaClassName is null then we assume that the current methodName\r
+                * is an alias and we must go to sysmethods to\r
+                * get the real method and java class names for this alias.\r
+                */\r
+               if (javaClassName == null)\r
+               {\r
+                       CompilerContext cc = getCompilerContext();\r
+\r
+                       // look for a routine\r
+\r
+                       String schemaName = procedureName.getSchemaName();\r
+                                                               \r
+                       boolean noSchema = schemaName == null;\r
+\r
+                       SchemaDescriptor sd = getSchemaDescriptor(schemaName, schemaName != null);\r
+\r
+            // The field methodName is used by resolveRoutine and\r
+            // is set to the name of the routine (procedureName.getTableName()).\r
+                       resolveRoutine(fromList, subqueryList, aggregateVector, sd);\r
+                       \r
+                       if (ad == null && noSchema && !forCallStatement)\r
+                       {\r
+                               // Resolve to a built-in SYSFUN function but only\r
+                               // if this is a function call and the call\r
+                               // was not qualified. E.g. COS(angle). The\r
+                               // SYSFUN functions are not in SYSALIASES but\r
+                               // an in-memory table, set up in DataDictioanryImpl.\r
+                               sd = getSchemaDescriptor("SYSFUN", true);\r
+                               \r
+                               resolveRoutine(fromList, subqueryList, aggregateVector, sd);\r
+                       }\r
+       \r
+\r
+                       /* Throw exception if no routine found */\r
+                       if (ad == null)\r
+                       {\r
+                               throw StandardException.newException(\r
+                        SQLState.LANG_NO_SUCH_METHOD_ALIAS, procedureName);\r
+                       }\r
+       \r
+\r
+\r
+                       /* Query is dependent on the AliasDescriptor */\r
+                       cc.createDependency(ad);\r
+\r
+\r
+                       methodName = ad.getAliasInfo().getMethodName();\r
+                       javaClassName = ad.getJavaClassName();\r
+            \r
+            // DERBY-2330 Do not allow a routine to resolve to\r
+            // a Java method that is part of the Derby runtime code base.\r
+            // This is a security measure to stop user-defined routines\r
+            // bypassing security by making calls directly to Derby's\r
+            // internal methods. E.g. open a table's conglomerate\r
+            // directly and read the file, bypassing any authorization.\r
+            // This is a simpler mechanism than analyzing all of\r
+            // Derby's public static methods and ensuring they have\r
+            // no Security holes.\r
+            if (javaClassName.startsWith("org.apache.derby."))\r
+            {\r
+                if (!sd.isSystemSchema())\r
+                    throw StandardException.newException(\r
+                        SQLState.LANG_TYPE_DOESNT_EXIST2, (Throwable) null,\r
+                        javaClassName);\r
+            }\r
+               }\r
+\r
+               verifyClassExist(javaClassName);\r
+\r
+               /* Resolve the method call */\r
+               resolveMethodCall(javaClassName, true);\r
+\r
+\r
+               alreadyBound = true;\r
+               if (isPrivilegeCollectionRequired())\r
+                       getCompilerContext().addRequiredRoutinePriv(ad);\r
+\r
+               // If this is a function call with a variable length\r
+               // return type, then we need to push a CAST node.\r
+               if (routineInfo != null)\r
+               {\r
+                       if (methodParms != null) \r
+                               optimizeDomainValueConversion();\r
+                       \r
+                       TypeDescriptor returnType = routineInfo.getReturnType();\r
+                       if (returnType != null)\r
+                       {\r
+                               TypeId returnTypeId = TypeId.getBuiltInTypeId(returnType.getJDBCTypeId());\r
+\r
+                               if (returnTypeId.variableLength()) {\r
+                                       // Cast the return using a cast node, but have to go\r
+                                       // into the SQL domain, and back to the Java domain.\r
+\r
+                                       DataTypeDescriptor returnValueDtd = new DataTypeDescriptor(\r
+                                                               returnTypeId,\r
+                                                               returnType.getPrecision(),\r
+                                                               returnType.getScale(),\r
+                                                               returnType.isNullable(),\r
+                                                               returnType.getMaximumWidth()\r
+                                                       );\r
+                                       // DERBY-2972  Match the collation of the RoutineAliasInfo              \r
+                                       returnValueDtd.setCollationType(returnType.getCollationType());\r
+                                        returnValueDtd.setCollationDerivation(StringDataValue.COLLATION_DERIVATION_IMPLICIT);\r
+                                       ValueNode returnValueToSQL = (ValueNode) getNodeFactory().getNode(\r
+                                                               C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+                                                               this, \r
+                                                               getContextManager());\r
+\r
+                                       ValueNode returnValueCastNode = (ValueNode) getNodeFactory().getNode(\r
+                                                                       C_NodeTypes.CAST_NODE,\r
+                                                                       returnValueToSQL, \r
+                                                                       returnValueDtd,\r
+                                                                       getContextManager());\r
+\r
+\r
+                                       JavaValueNode returnValueToJava = (JavaValueNode) getNodeFactory().getNode(\r
+                                                                               C_NodeTypes.SQL_TO_JAVA_VALUE_NODE,\r
+                                                                               returnValueCastNode, \r
+                                                                               getContextManager());\r
+                                       returnValueToJava.setCollationType(returnType.getCollationType());\r
+                                       return returnValueToJava.bindExpression(fromList, subqueryList, aggregateVector);\r
+                               }\r
+\r
+                       }\r
+               }\r
+\r
+               return this;\r
+       }\r
+\r
+       /**\r
+        * If this SQL function has parameters which are SQLToJavaValueNode over\r
+        * JavaToSQLValueNode and the java value node underneath is a SQL function\r
+        * defined with CALLED ON NULL INPUT, then we can get rid of the wrapper\r
+        * nodes over the java value node for such parameters. This is because\r
+        * SQL functions defined with CALLED ON NULL INPUT need access to only\r
+        * java domain values.\r
+        * This can't be done for parameters which are wrappers over SQL function\r
+        * defined with RETURN NULL ON NULL INPUT because such functions need\r
+        * access to both sql domain value and java domain value. - Derby479\r
+        */\r
+       private void optimizeDomainValueConversion() throws StandardException {\r
+               int             count = methodParms.length;\r
+               for (int parm = 0; parm < count; parm++)\r
+               {\r
+                       if (methodParms[parm] instanceof SQLToJavaValueNode &&\r
+                               ((SQLToJavaValueNode)methodParms[parm]).getSQLValueNode() instanceof\r
+                               JavaToSQLValueNode)\r
+                       {\r
+                               //If we are here, then it means that the parameter is\r
+                               //SQLToJavaValueNode on top of JavaToSQLValueNode\r
+                               JavaValueNode paramIsJavaValueNode =\r
+                                       ((JavaToSQLValueNode)((SQLToJavaValueNode)methodParms[parm]).getSQLValueNode()).getJavaValueNode();\r
+                               if (paramIsJavaValueNode instanceof StaticMethodCallNode)\r
+                               {\r
+                                       //If we are here, then it means that the parameter has\r
+                                       //a MethodCallNode underneath it.\r
+                                       StaticMethodCallNode paramIsMethodCallNode = (StaticMethodCallNode)paramIsJavaValueNode;\r
+                                       //If the MethodCallNode parameter is defined as\r
+                                       //CALLED ON NULL INPUT, then we can remove the wrappers\r
+                                       //for the param and just set the parameter to the\r
+                                       //java value node.\r
+                                       if (paramIsMethodCallNode.routineInfo != null &&\r
+                                                       paramIsMethodCallNode.routineInfo.calledOnNullInput())\r
+                                               methodParms[parm] =\r
+                                                       ((JavaToSQLValueNode)((SQLToJavaValueNode)methodParms[parm]).getSQLValueNode()).getJavaValueNode();\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Resolve a routine. Obtain a list of routines from the data dictionary\r
+        * of the correct type (functions or procedures) and name.\r
+        * Pick the best routine from the list. Currently only a single routine\r
+        * with a given type and name is allowed, thus if changes are made to\r
+        * support overloaded routines, careful code inspection and testing will\r
+        * be required.\r
+        * @param fromList\r
+        * @param subqueryList\r
+        * @param aggregateVector\r
+        * @param sd\r
+        * @throws StandardException\r
+        */\r
+       private void resolveRoutine(FromList fromList, SubqueryList subqueryList, Vector aggregateVector, SchemaDescriptor sd) throws StandardException {\r
+               if (sd.getUUID() != null) {\r
+\r
+               java.util.List list = getDataDictionary().getRoutineList(\r
+                       sd.getUUID().toString(), methodName,\r
+                       forCallStatement ? AliasInfo.ALIAS_NAME_SPACE_PROCEDURE_AS_CHAR : AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR\r
+                       );\r
+\r
+               for (int i = list.size() - 1; i >= 0; i--) {\r
+\r
+                       AliasDescriptor proc = (AliasDescriptor) list.get(i);\r
+\r
+                       RoutineAliasInfo routineInfo = (RoutineAliasInfo) proc.getAliasInfo();\r
+                       int parameterCount = routineInfo.getParameterCount();\r
+                       if (parameterCount != methodParms.length)\r
+                               continue;\r
+\r
+                       // pre-form the method signature. If it is a dynamic result set procedure\r
+                       // then we need to add in the ResultSet array\r
+\r
+                       TypeDescriptor[] parameterTypes = routineInfo.getParameterTypes();\r
+\r
+                       int sigParameterCount = parameterCount;\r
+                       if (routineInfo.getMaxDynamicResultSets() > 0)\r
+                               sigParameterCount++;\r
+\r
+                       signature = new JSQLType[sigParameterCount];\r
+                       for (int p = 0; p < parameterCount; p++) {\r
+\r
+                               // find the declared type.\r
+\r
+                               TypeDescriptor td = parameterTypes[p];\r
+\r
+                               TypeId typeId = TypeId.getBuiltInTypeId(td.getJDBCTypeId());\r
+\r
+                               TypeId parameterTypeId = typeId;\r
+\r
+\r
+                               // if it's an OUT or INOUT parameter we need an array.\r
+                               int parameterMode = routineInfo.getParameterModes()[p];\r
+\r
+                               if (parameterMode != JDBC30Translation.PARAMETER_MODE_IN) {\r
+\r
+                                       String arrayType;\r
+                                       switch (typeId.getJDBCTypeId()) {\r
+                                               case java.sql.Types.SMALLINT:\r
+                                               case java.sql.Types.INTEGER:\r
+                                               case java.sql.Types.BIGINT:\r
+                                               case java.sql.Types.REAL:\r
+                                               case java.sql.Types.DOUBLE:\r
+                                                       arrayType = getTypeCompiler(typeId).getCorrespondingPrimitiveTypeName().concat("[]");\r
+                                                       break;\r
+                                               default:\r
+                                                       arrayType = typeId.getCorrespondingJavaTypeName().concat("[]");\r
+                                                       break;\r
+                                       }\r
+\r
+                                       typeId = TypeId.getUserDefinedTypeId(arrayType, false);\r
+                               }\r
+\r
+                               // this is the type descriptor of the require method parameter\r
+                               DataTypeDescriptor methoddtd = new DataTypeDescriptor(\r
+                                               typeId,\r
+                                               td.getPrecision(),\r
+                                               td.getScale(),\r
+                                               td.isNullable(),\r
+                                               td.getMaximumWidth()\r
+                                       );\r
+\r
+                               signature[p] = new JSQLType(methoddtd);\r
+\r
+                               // check parameter is a ? node for INOUT and OUT parameters.\r
+\r
+                               ValueNode sqlParamNode = null;\r
+\r
+                               if (methodParms[p] instanceof SQLToJavaValueNode) {\r
+                                       SQLToJavaValueNode sql2j = (SQLToJavaValueNode) methodParms[p];\r
+                                       sqlParamNode = sql2j.getSQLValueNode();\r
+                               }\r
+                               else\r
+                               {\r
+                               }\r
+\r
+                               boolean isParameterMarker = true;\r
+                               if ((sqlParamNode == null) || !sqlParamNode.requiresTypeFromContext())\r
+                               {\r
+                                       if (parameterMode != JDBC30Translation.PARAMETER_MODE_IN) {\r
+                                        \r
+                                               throw StandardException.newException(SQLState.LANG_DB2_PARAMETER_NEEDS_MARKER,\r
+                                                       RoutineAliasInfo.parameterMode(parameterMode),\r
+                                                       routineInfo.getParameterNames()[p]);\r
+                                       }\r
+                                       isParameterMarker = false;\r
+                               }\r
+                               else\r
+                               {\r
+                                       if (applicationParameterNumbers == null)\r
+                                               applicationParameterNumbers = new int[parameterCount];\r
+                                       if (sqlParamNode instanceof UnaryOperatorNode) {\r
+                                               ParameterNode pn = ((UnaryOperatorNode)sqlParamNode).getParameterOperand();\r
+                                               applicationParameterNumbers[p] = pn.getParameterNumber();\r
+                                       } else\r
+                                               applicationParameterNumbers[p] = ((ParameterNode) sqlParamNode).getParameterNumber();\r
+                               }\r
+\r
+                               // this is the SQL type of the procedure parameter.\r
+                               DataTypeDescriptor paramdtd = new DataTypeDescriptor(\r
+                                       parameterTypeId,\r
+                                       td.getPrecision(),\r
+                                       td.getScale(),\r
+                                       td.isNullable(),\r
+                                       td.getMaximumWidth()\r
+                               );\r
+\r
+                               boolean needCast = false;\r
+                               if (!isParameterMarker)\r
+                               {\r
+\r
+                                       // can only be an IN parameter.\r
+                                       // check that the value can be assigned to the\r
+                                       // type of the procedure parameter.\r
+                                       if (sqlParamNode instanceof UntypedNullConstantNode)\r
+                                       {\r
+                                               sqlParamNode.setType(paramdtd);\r
+                                       }\r
+                                       else\r
+                                       {\r
+\r
+\r
+                                               DataTypeDescriptor dts;\r
+                                               TypeId argumentTypeId;\r
+\r
+                                               if (sqlParamNode != null)\r
+                                               {\r
+                                                       // a node from the SQL world\r
+                                                       argumentTypeId = sqlParamNode.getTypeId();\r
+                                                       dts = sqlParamNode.getTypeServices();\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       // a node from the Java world\r
+                                                       dts = DataTypeDescriptor.getSQLDataTypeDescriptor(methodParms[p].getJavaTypeName());\r
+                                                       if (dts == null)\r
+                                                       {\r
+                                                               throw StandardException.newException(SQLState.LANG_NO_CORRESPONDING_S_Q_L_TYPE, \r
+                                                                       methodParms[p].getJavaTypeName());\r
+                                                       }\r
+\r
+                                                       argumentTypeId = dts.getTypeId();\r
+                                               }\r
+\r
+                                               if (! getTypeCompiler(parameterTypeId).storable(argumentTypeId, getClassFactory()))\r
+                                                               throw StandardException.newException(SQLState.LANG_NOT_STORABLE, \r
+                                                                       parameterTypeId.getSQLTypeName(),\r
+                                                                       argumentTypeId.getSQLTypeName() );\r
+\r
+                                               // if it's not an exact length match then some cast will be needed.\r
+                                               if (!paramdtd.isExactTypeAndLengthMatch(dts))\r
+                                                       needCast = true;\r
+                                       }\r
+                               }\r
+                               else\r
+                               {\r
+                                       // any variable length type will need a cast from the\r
+                                       // Java world (the ? parameter) to the SQL type. This\r
+                                       // ensures values like CHAR(10) are passed into the procedure\r
+                                       // correctly as 10 characters long.\r
+                                       if (parameterTypeId.variableLength()) {\r
+\r
+                                               if (parameterMode != JDBC30Translation.PARAMETER_MODE_OUT)\r
+                                                       needCast = true;\r
+                                       }\r
+                               }\r
+                               \r
+\r
+                               if (needCast)\r
+                               {\r
+                                       // push a cast node to ensure the\r
+                                       // correct type is passed to the method\r
+                                       // this gets tacky because before we knew\r
+                                       // it was a procedure call we ensured all the\r
+                                       // parameter are JavaNodeTypes. Now we need to\r
+                                       // push them back to the SQL domain, cast them\r
+                                       // and then push them back to the Java domain.\r
+\r
+                                       if (sqlParamNode == null) {\r
+\r
+                                               sqlParamNode = (ValueNode) getNodeFactory().getNode(\r
+                                                       C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,\r
+                                                       methodParms[p], \r
+                                                       getContextManager());\r
+                                       }\r
+\r
+                                       ValueNode castNode = (ValueNode) getNodeFactory().getNode(\r
+                                               C_NodeTypes.CAST_NODE,\r
+                                               sqlParamNode, \r
+                                               paramdtd,\r
+                                               getContextManager());\r
+\r
+\r
+                                       methodParms[p] = (JavaValueNode) getNodeFactory().getNode(\r
+                                                       C_NodeTypes.SQL_TO_JAVA_VALUE_NODE,\r
+                                                       castNode, \r
+                                                       getContextManager());\r
+\r
+                                       methodParms[p] = methodParms[p].bindExpression(fromList, subqueryList, aggregateVector);\r
+                               }\r
+\r
+                               // only force the type for a ? so that the correct type shows up\r
+                               // in parameter meta data\r
+                               if (isParameterMarker)\r
+                                       sqlParamNode.setType(paramdtd);\r
+                       }\r
+\r
+                       if (sigParameterCount != parameterCount) {\r
+\r
+                               TypeId typeId = TypeId.getUserDefinedTypeId("java.sql.ResultSet[]", false);\r
+\r
+                               DataTypeDescriptor dtd = new DataTypeDescriptor(\r
+                                               typeId,\r
+                                               0,\r
+                                               0,\r
+                                               false,\r
+                                               -1\r
+                                       );\r
+\r
+                               signature[parameterCount] = new JSQLType(dtd);\r
+\r
+                       }\r
+\r
+                       this.routineInfo = routineInfo;\r
+                       ad = proc;\r
+\r
+                       // If a procedure is in the system schema and defined as executing\r
+                       // SQL do we set we are in system code.\r
+                       if (sd.isSystemSchema() && (routineInfo.getReturnType() == null) && routineInfo.getSQLAllowed() != RoutineAliasInfo.NO_SQL)\r
+                               isSystemCode = true;\r
+\r
+                       break;\r
+               }\r
+}\r
+       }\r
+\r
+       /**\r
+               Push extra code to generate the casts within the\r
+               arrays for the parameters passed as arrays.\r
+       */\r
+       public  void generateOneParameter(ExpressionClassBuilder acb,\r
+                                                                                       MethodBuilder mb,\r
+                                                                                       int parameterNumber )\r
+                       throws StandardException\r
+       {\r
+               int parameterMode;\r
+\r
+               SQLToJavaValueNode sql2j = null;\r
+               if (methodParms[parameterNumber] instanceof SQLToJavaValueNode)\r
+                       sql2j = (SQLToJavaValueNode) methodParms[parameterNumber];\r
+               \r
+               if (routineInfo != null) {\r
+                       parameterMode = routineInfo.getParameterModes()[parameterNumber];\r
+               } else {\r
+                       // for a static method call the parameter always starts out as a in parameter, but\r
+                       // may be registered as an IN OUT parameter. For a static method argument to be\r
+                       // a dynmaically registered out parameter it must be a simple ? parameter\r
+\r
+                       parameterMode = JDBC30Translation.PARAMETER_MODE_IN;\r
+\r
+                       if (sql2j != null) {\r
+                               if (sql2j.getSQLValueNode().requiresTypeFromContext()) {\r
+                                       ParameterNode pn;\r
+                                       if (sql2j.getSQLValueNode() instanceof UnaryOperatorNode) \r
+                                               pn = ((UnaryOperatorNode)sql2j.getSQLValueNode()).getParameterOperand();\r
+                                       else\r
+                                               pn = (ParameterNode) (sql2j.getSQLValueNode());\r
+\r
+                                       // applicationParameterNumbers is only set up for a procedure.\r
+                                       int applicationParameterNumber = pn.getParameterNumber();\r
+\r
+                                       String parameterType = methodParameterTypes[parameterNumber];\r
+\r
+                                       if (parameterType.endsWith("[]")) {\r
+\r
+                                               // constructor  - setting up correct paramter type info\r
+                                               MethodBuilder constructor = acb.getConstructor();\r
+                                               acb.pushThisAsActivation(constructor);\r
+                                               constructor.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                                       "getParameterValueSet", ClassName.ParameterValueSet, 0);\r
+\r
+                                               constructor.push(applicationParameterNumber);\r
+                                               constructor.push(JDBC30Translation.PARAMETER_MODE_UNKNOWN);\r
+                                               constructor.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                                       "setParameterMode", "void", 2);\r
+                                               constructor.endStatement();\r
+                                       }\r
+                               }\r
+                       } \r
+               }\r
+\r
+               switch (parameterMode) {\r
+               case JDBC30Translation.PARAMETER_MODE_IN:\r
+               case JDBC30Translation.PARAMETER_MODE_IN_OUT:\r
+               case JDBC30Translation.PARAMETER_MODE_UNKNOWN:\r
+                       if (sql2j != null)\r
+                               sql2j.returnsNullOnNullState = returnsNullOnNullState;\r
+                       super.generateOneParameter(acb, mb, parameterNumber);\r
+                       break;\r
+\r
+               case JDBC30Translation.PARAMETER_MODE_OUT:\r
+                       // For an OUT parameter we require nothing to be pushed into the\r
+                       // method call from the parameter node.\r
+                       break;\r
+               }\r
+\r
+               switch (parameterMode) {\r
+               case JDBC30Translation.PARAMETER_MODE_IN:\r
+               case JDBC30Translation.PARAMETER_MODE_UNKNOWN:\r
+                       break;\r
+\r
+               case JDBC30Translation.PARAMETER_MODE_IN_OUT:\r
+               case JDBC30Translation.PARAMETER_MODE_OUT:\r
+               {\r
+                       // Create the array used to pass into the method. We create a\r
+                       // new array for each call as there is a small chance the\r
+                       // application could retain a reference to it and corrupt\r
+                       // future calls with the same CallableStatement object.\r
+\r
+                       String methodParameterType = methodParameterTypes[parameterNumber];\r
+                       String arrayType = methodParameterType.substring(0, methodParameterType.length() - 2);\r
+                       LocalField lf = acb.newFieldDeclaration(Modifier.PRIVATE, methodParameterType);\r
+\r
+                       if (outParamArrays == null)\r
+                               outParamArrays = new LocalField[methodParms.length];\r
+\r
+                       outParamArrays[parameterNumber] = lf;\r
+\r
+                       mb.pushNewArray(arrayType, 1);\r
+                       mb.putField(lf);\r
+\r
+                       // set the IN part of the parameter into the INOUT parameter.\r
+                       if (parameterMode != JDBC30Translation.PARAMETER_MODE_OUT) {\r
+                               mb.swap();\r
+                               mb.setArrayElement(0);\r
+                               mb.getField(lf);\r
+                       }\r
+                       break;\r
+                       }\r
+               }\r
+\r
+       }\r
+\r
+       /**\r
+        * Categorize this predicate.  Initially, this means\r
+        * building a bit map of the referenced tables for each predicate.\r
+        * If the source of this ColumnReference (at the next underlying level) \r
+        * is not a ColumnReference or a VirtualColumnNode then this predicate\r
+        * will not be pushed down.\r
+        *\r
+        * For example, in:\r
+        *              select * from (select 1 from s) a (x) where x = 1\r
+        * we will not push down x = 1.\r
+        * NOTE: It would be easy to handle the case of a constant, but if the\r
+        * inner SELECT returns an arbitrary expression, then we would have to copy\r
+        * that tree into the pushed predicate, and that tree could contain\r
+        * subqueries and method calls.\r
+        * RESOLVE - revisit this issue once we have views.\r
+        *\r
+        * @param referencedTabs        JBitSet with bit map of referenced FromTables\r
+        * @param simplePredsOnly       Whether or not to consider method\r
+        *                                                      calls, field references and conditional nodes\r
+        *                                                      when building bit map\r
+        *\r
+        * @return boolean              Whether or not source.expression is a ColumnReference\r
+        *                                              or a VirtualColumnNode.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)\r
+               throws StandardException\r
+       {\r
+               /* We stop here when only considering simple predicates\r
+                *  as we don't consider method calls when looking\r
+                * for null invariant predicates.\r
+                */\r
+               if (simplePredsOnly)\r
+               {\r
+                       return false;\r
+               }\r
+\r
+               boolean pushable = true;\r
+\r
+               pushable = pushable && super.categorize(referencedTabs, simplePredsOnly);\r
+\r
+               return pushable;\r
+       }\r
+\r
+       /**\r
+        * Convert this object to a String.  See comments in QueryTreeNode.java\r
+        * for how this should be done for tree printing.\r
+        *\r
+        * @return      This object as a String\r
+        */\r
+\r
+       public String toString()\r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       return "javaClassName: " +\r
+                               (javaClassName != null ? javaClassName : "null") + "\n" +\r
+                               super.toString();\r
+               }\r
+               else\r
+               {\r
+                       return "";\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Do code generation for this method call\r
+        *\r
+        * @param acb   The ExpressionClassBuilder for the class we're generating\r
+        * @param mb    The method the expression will go into\r
+        *\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public void generateExpression(ExpressionClassBuilder acb,\r
+                                                                                       MethodBuilder mb)\r
+                                                                       throws StandardException\r
+       {\r
+               if (routineInfo != null) {\r
+\r
+                       if (!routineInfo.calledOnNullInput() && routineInfo.getParameterCount() != 0)\r
+                               returnsNullOnNullState = acb.newFieldDeclaration(Modifier.PRIVATE, "boolean");\r
+\r
+               }\r
+\r
+               // reset the parameters are null indicator.\r
+               if (returnsNullOnNullState != null) {\r
+                       mb.push(false);\r
+                       mb.setField(returnsNullOnNullState);\r
+\r
+                       // for the call to the generated method below.\r
+                       mb.pushThis();\r
+               }\r
+\r
+               int nargs = generateParameters(acb, mb);\r
+\r
+               LocalField functionEntrySQLAllowed = null;\r
+\r
+               if (routineInfo != null) {\r
+\r
+                       short sqlAllowed = routineInfo.getSQLAllowed();\r
+\r
+                       // Before we set up our authorization level, add a check to see if this\r
+                       // method can be called. If the routine is NO SQL or CONTAINS SQL \r
+                       // then there is no need for a check. As follows:\r
+                       //\r
+                       // Current Level = NO_SQL - CALL will be rejected when getting CALL result set\r
+                       // Current Level = anything else - calls to procedures defined as NO_SQL and CONTAINS SQL both allowed.\r
+\r
+\r
+                       if (sqlAllowed != RoutineAliasInfo.NO_SQL)\r
+                       {\r
+                               \r
+                               int sqlOperation;\r
+                               \r
+                               if (sqlAllowed == RoutineAliasInfo.READS_SQL_DATA)\r
+                                       sqlOperation = Authorizer.SQL_SELECT_OP;\r
+                               else if (sqlAllowed == RoutineAliasInfo.MODIFIES_SQL_DATA)\r
+                                       sqlOperation = Authorizer.SQL_WRITE_OP;\r
+                               else\r
+                                       sqlOperation = Authorizer.SQL_ARBITARY_OP;\r
+                               \r
+                               generateAuthorizeCheck((ActivationClassBuilder) acb, mb, sqlOperation);\r
+                       }\r
+\r
+                       int statmentContextReferences = isSystemCode ? 2 : 1;\r
+                       \r
+                       boolean isFunction = routineInfo.getReturnType() != null;\r
+\r
+                       if (isFunction)\r
+                               statmentContextReferences++;\r
+\r
+\r
+                       if (statmentContextReferences != 0) {\r
+                               acb.pushThisAsActivation(mb);\r
+                               mb.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                       "getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);\r
+                               mb.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                       "getStatementContext", "org.apache.derby.iapi.sql.conn.StatementContext", 0);\r
+\r
+                               for (int scc = 1; scc < statmentContextReferences; scc++)\r
+                                       mb.dup();\r
+                       }\r
+\r
+                       /**\r
+                               Set the statement context to reflect we are running\r
+                               System procedures, so that we can execute non-standard SQL.\r
+                       */\r
+                       if (isSystemCode) {\r
+                               mb.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                       "setSystemCode", "void", 0);\r
+                       }\r
+\r
+                       // for a function we need to fetch the current SQL control\r
+                       // so that we can reset it once the function is complete.\r
+                       // \r
+                       if (isFunction)\r
+                       {\r
+                               functionEntrySQLAllowed = acb.newFieldDeclaration(Modifier.PRIVATE, "short");\r
+                               mb.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                       "getSQLAllowed", "short", 0);\r
+                               mb.setField(functionEntrySQLAllowed);\r
+\r
+                       }\r
+                       \r
+                       \r
+                       // Set up the statement context to reflect the\r
+                       // restricted SQL execution allowed by this routine.\r
+\r
+                       mb.push(sqlAllowed);\r
+                       mb.push(false);\r
+                       mb.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                               "setSQLAllowed", "void", 2);\r
+\r
+               }\r
+\r
+               // add in the ResultSet arrays.\r
+               if (routineInfo != null) {\r
+\r
+                       int compiledResultSets = methodParameterTypes.length - methodParms.length;\r
+\r
+                       if (compiledResultSets != 0) {\r
+\r
+                               // Add a method that indicates the maxium number of dynamic result sets.\r
+                               int maxDynamicResults = routineInfo.getMaxDynamicResultSets();\r
+                               if (maxDynamicResults > 0) {\r
+                                       MethodBuilder gdr = acb.getClassBuilder().newMethodBuilder(Modifier.PUBLIC, "int", "getMaxDynamicResults");\r
+                                       gdr.push(maxDynamicResults);\r
+                                       gdr.methodReturn();\r
+                                       gdr.complete();\r
+                               }\r
+\r
+                               // add a method to return all the dynamic result sets (unordered)\r
+                               MethodBuilder gdr = acb.getClassBuilder().newMethodBuilder(Modifier.PUBLIC, "java.sql.ResultSet[][]", "getDynamicResults");\r
+\r
+                               MethodBuilder cons = acb.getConstructor();\r
+                               // if (procDef.getParameterStyle() == RoutineAliasInfo.PS_JAVA)\r
+                               {\r
+                                       // PARAMETER STYLE JAVA\r
+\r
+                                       LocalField procedureResultSetsHolder = acb.newFieldDeclaration(Modifier.PRIVATE, "java.sql.ResultSet[][]");\r
+\r
+                                       // getDynamicResults body\r
+                                       gdr.getField(procedureResultSetsHolder);\r
+\r
+                                       // create the holder of all the ResultSet arrays, new java.sql.ResultSet[][compiledResultSets]\r
+                                       cons.pushNewArray("java.sql.ResultSet[]", compiledResultSets);\r
+                                       cons.setField(procedureResultSetsHolder);\r
+\r
+\r
+                                       // arguments for the dynamic result sets\r
+                                       for (int i = 0; i < compiledResultSets; i++) {\r
+\r
+                                               mb.pushNewArray("java.sql.ResultSet", 1);\r
+                                               mb.dup();\r
+\r
+                                               mb.getField(procedureResultSetsHolder);\r
+                                               mb.swap();\r
+\r
+                                               mb.setArrayElement(i);\r
+                                       }\r
+                               } \r
+\r
+                               // complete the method that returns the ResultSet[][] to the \r
+                               gdr.methodReturn();\r
+                               gdr.complete();\r
+\r
+                               nargs += compiledResultSets;\r
+                       }\r
+\r
+               }\r
+\r
+               String javaReturnType = getJavaTypeName();\r
+\r
+               MethodBuilder mbnc = null;\r
+               MethodBuilder mbcm = mb;\r
+\r
+\r
+               // If any of the parameters are null then\r
+               // do not call the method, just return null.\r
+               if (returnsNullOnNullState != null)\r
+               {\r
+                       mbnc = acb.newGeneratedFun(javaReturnType, Modifier.PRIVATE, methodParameterTypes);\r
+\r
+                       // add the throws clause for the public static method we are going to call.\r
+                       Class[] throwsSet = ((java.lang.reflect.Method) method).getExceptionTypes();\r
+                       for (int te = 0; te < throwsSet.length; te++)\r
+                       {\r
+                               mbnc.addThrownException(throwsSet[te].getName());\r
+                       }\r
+\r
+                       mbnc.getField(returnsNullOnNullState);\r
+                       mbnc.conditionalIf();\r
+\r
+                       // set up for a null!!\r
+                       // for objects is easy.\r
+                       mbnc.pushNull(javaReturnType);\r
+\r
+                       mbnc.startElseCode();   \r
+\r
+                       if (!actualMethodReturnType.equals(javaReturnType))\r
+                               mbnc.pushNewStart(javaReturnType);\r
+\r
+                       // fetch all the arguments\r
+                       for (int pa = 0; pa < nargs; pa++)\r
+                       {\r
+                               mbnc.getParameter(pa);\r
+                       }\r
+\r
+                       mbcm = mbnc;\r
+               }\r
+\r
+               mbcm.callMethod(VMOpcode.INVOKESTATIC, method.getDeclaringClass().getName(), methodName,\r
+                                       actualMethodReturnType, nargs);\r
+\r
+\r
+               if (returnsNullOnNullState != null)\r
+               {\r
+                       if (!actualMethodReturnType.equals(javaReturnType))\r
+                               mbnc.pushNewComplete(1);\r
+\r
+                       mbnc.completeConditional();\r
+\r
+                       mbnc.methodReturn();\r
+                       mbnc.complete();\r
+\r
+                       // now call the wrapper method\r
+                       mb.callMethod(VMOpcode.INVOKEVIRTUAL, acb.getClassBuilder().getFullName(), mbnc.getName(),\r
+                                       javaReturnType, nargs);\r
+                       mbnc = null;\r
+               }\r
+\r
+\r
+               if (routineInfo != null) {\r
+\r
+                       // reset the SQL allowed setting that we set upon\r
+                       // entry to the method.\r
+                       if (functionEntrySQLAllowed != null) {\r
+                               acb.pushThisAsActivation(mb);\r
+                               mb.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                       "getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);\r
+                               mb.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                       "getStatementContext", "org.apache.derby.iapi.sql.conn.StatementContext", 0);\r
+                               mb.getField(functionEntrySQLAllowed);\r
+                               mb.push(true); // override as we are ending the control set by this function all.\r
+                               mb.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                       "setSQLAllowed", "void", 2);\r
+\r
+                       }\r
+\r
+                       if (outParamArrays != null) {\r
+\r
+                               MethodBuilder constructor = acb.getConstructor();\r
+\r
+                               // constructor  - setting up correct paramter type info\r
+                               acb.pushThisAsActivation(constructor);\r
+                               constructor.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                       "getParameterValueSet", ClassName.ParameterValueSet, 0);\r
+\r
+                               // execute  - passing out parameters back.\r
+                               acb.pushThisAsActivation(mb);\r
+                               mb.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                       "getParameterValueSet", ClassName.ParameterValueSet, 0);\r
+\r
+                               int[] parameterModes = routineInfo.getParameterModes();\r
+                               for (int i = 0; i < outParamArrays.length; i++) {\r
+\r
+                                       int parameterMode = parameterModes[i];\r
+                                       if (parameterMode != JDBC30Translation.PARAMETER_MODE_IN) {\r
+\r
+                                               // must be a parameter if it is INOUT or OUT.\r
+                                               ValueNode sqlParamNode = ((SQLToJavaValueNode) methodParms[i]).getSQLValueNode();\r
+\r
+\r
+                                               int applicationParameterNumber = applicationParameterNumbers[i];\r
+\r
+                                               // Set the correct parameter nodes in the ParameterValueSet at constructor time.\r
+                                               constructor.dup();\r
+                                               constructor.push(applicationParameterNumber);\r
+                                               constructor.push(parameterMode);\r
+                                               constructor.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                               "setParameterMode", "void", 2);\r
+\r
+                                               // Pass the value of the outparameters back to the calling code\r
+                                               LocalField lf = outParamArrays[i];\r
+\r
+                                               mb.dup(); \r
+                                               mb.push(applicationParameterNumber);\r
+                                               mb.callMethod(VMOpcode.INVOKEINTERFACE, null,\r
+                                                                       "getParameter", ClassName.DataValueDescriptor, 1);\r
+\r
+                                               // see if we need to set the desired length/scale/precision of the type\r
+                                               DataTypeDescriptor paramdtd = sqlParamNode.getTypeServices();\r
+\r
+                                               boolean isNumericType = paramdtd.getTypeId().isNumericTypeId();\r
+\r
+                                               // is the underlying type for the OUT/INOUT parameter primitive.\r
+                                               boolean isPrimitive = ((java.lang.reflect.Method) method).getParameterTypes()[i].getComponentType().isPrimitive();\r
+\r
+                                               if (isNumericType) {\r
+                                                       // need to up-cast as the setValue(Number) method only exists on NumberDataValue\r
+\r
+                                                       if (!isPrimitive)\r
+                                                               mb.cast(ClassName.NumberDataValue);\r
+                                               }\r
+                                               else if (paramdtd.getTypeId().isBooleanTypeId())\r
+                                               {\r
+                                                       // need to cast as the setValue(Boolean) method only exists on BooleanDataValue\r
+                                                       if (!isPrimitive)\r
+                                                               mb.cast(ClassName.BooleanDataValue);\r
+                                               }\r
+\r
+                                               if (paramdtd.getTypeId().variableLength()) {\r
+                                                       // need another DVD reference for the set width below.\r
+                                                       mb.dup();\r
+                                               }\r
+\r
+\r
+                                               mb.getField(lf); // pvs, dvd, array\r
+                                               mb.getArrayElement(0); // pvs, dvd, value\r
+\r
+                                               // The value needs to be set thorugh the setValue(Number) method.\r
+                                               if (isNumericType && !isPrimitive)\r
+                                               {\r
+                                                       mb.upCast("java.lang.Number");\r
+                                               }\r
+\r
+                                               mb.callMethod(VMOpcode.INVOKEINTERFACE, null, "setValue", "void", 1);\r
+\r
+                                               if (paramdtd.getTypeId().variableLength()) {\r
+                                                       mb.push(isNumericType ? paramdtd.getPrecision() : paramdtd.getMaximumWidth());\r
+                                                       mb.push(paramdtd.getScale());\r
+                                                       mb.push(isNumericType);\r
+                                                       mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue, "setWidth", "void", 3);\r
+                                                       // mb.endStatement();\r
+                                               }\r
+                                       }\r
+                               }\r
+                               constructor.endStatement();\r
+                               mb.endStatement();\r
+                       }\r
+\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Set default privilege of EXECUTE for this node. \r
+        */\r
+       int getPrivType()\r
+       {\r
+               return Authorizer.EXECUTE_PRIV;\r
+       }\r
+}\r