Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / compile / MethodCallNode.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java
new file mode 100644 (file)
index 0000000..43f8126
--- /dev/null
@@ -0,0 +1,1198 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.MethodCallNode\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.loader.ClassInspector;\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.error.StandardException;\r
+\r
+import org.apache.derby.iapi.types.StringDataValue;\r
+import org.apache.derby.iapi.types.TypeId;\r
+import org.apache.derby.iapi.types.JSQLType;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+\r
+import org.apache.derby.iapi.sql.compile.Visitable;\r
+import org.apache.derby.iapi.sql.compile.Visitor;\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+import org.apache.derby.iapi.sql.compile.CompilerContext;\r
+\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+\r
+import org.apache.derby.iapi.sql.compile.TypeCompiler;\r
+import org.apache.derby.catalog.TypeDescriptor;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.reference.JDBC30Translation;\r
+\r
+import org.apache.derby.iapi.store.access.Qualifier;\r
+\r
+import org.apache.derby.iapi.util.JBitSet;\r
+\r
+import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;\r
+import org.apache.derby.catalog.types.RoutineAliasInfo;\r
+\r
+import java.lang.reflect.Modifier;\r
+import java.lang.reflect.Member;\r
+\r
+import java.util.StringTokenizer;\r
+import java.util.Vector;\r
+\r
+/**\r
+ * A MethodCallNode represents a Java method call.  Method calls can be done\r
+ * through DML (as expressions) or through the CALL statement.\r
+ *\r
+ */\r
+\r
+abstract class MethodCallNode extends JavaValueNode\r
+{\r
+       /*\r
+       ** Name of the method.\r
+       */\r
+        String methodName;\r
+\r
+    /** The name of the class containing the method. May not be known until bindExpression() has been called.\r
+     * @see #bindExpression\r
+     * @see #getJavaClassName()\r
+     */\r
+    String javaClassName;\r
+       \r
+       /**\r
+               For a procedure or function call\r
+       */\r
+       RoutineAliasInfo routineInfo;\r
+\r
+\r
+       /**\r
+               True if this is an internal call, just used to set up a generated method call.\r
+       */\r
+       boolean internalCall;\r
+\r
+       /**\r
+               For resolution of procedure INOUT/OUT parameters to the primitive\r
+               form, such as int[]. May be null.\r
+       */\r
+       private String[] procedurePrimitiveArrayType;\r
+\r
+       // bound signature of arguments, stated in universal types (JSQLType)\r
+       protected JSQLType[]                            signature;\r
+\r
+       /*\r
+       ** Parameters to the method, if any.  No elements if no parameters.\r
+       */\r
+       protected JavaValueNode[]       methodParms;\r
+\r
+       /* The method call */\r
+       protected Member method;\r
+\r
+       protected String actualMethodReturnType;\r
+\r
+       /**\r
+               The parameter types for the resolved method.\r
+       */\r
+       String[] methodParameterTypes;\r
+\r
+       /**\r
+        * Initializer for a MethodCallNode\r
+        *\r
+        * @param       methodName      The name of the method to call\r
+        */\r
+       public void init(Object methodName)\r
+       {\r
+               this.methodName = (String) methodName;\r
+       }\r
+\r
+       public String getMethodName()\r
+       {\r
+               return  methodName;\r
+       }\r
+\r
+    /**\r
+     * @return the name of the class that contains the method, null if not known. It may not be known\r
+     *         until this node has been bound.\r
+     */\r
+    public String getJavaClassName()\r
+    {\r
+        return javaClassName;\r
+    }\r
+\r
+       /**\r
+        * Add the parameter list\r
+        *\r
+        * @param parameterList         A Vector of the parameters\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void addParms(Vector parameterList) throws StandardException\r
+       {\r
+               methodParms = new JavaValueNode[parameterList.size()];\r
+\r
+               int     plSize = parameterList.size();\r
+               for (int index = 0; index < plSize; index++)\r
+               {\r
+                       QueryTreeNode   qt;\r
+\r
+                       qt = (QueryTreeNode) parameterList.elementAt(index);\r
+\r
+                       /*\r
+                       ** Since we need the parameter to be in Java domain format, put a\r
+                       ** SQLToJavaValueNode on top of the parameter node if it is a \r
+                       ** SQLValueNode. But if the parameter is already in Java domain \r
+                       ** format, then we don't need to do anything.\r
+                       */\r
+                       if ( ! (qt instanceof JavaValueNode))\r
+                       {\r
+                               qt = (SQLToJavaValueNode) getNodeFactory().getNode(\r
+                                               C_NodeTypes.SQL_TO_JAVA_VALUE_NODE, \r
+                                               qt, \r
+                                               getContextManager());\r
+                       }\r
+\r
+                       methodParms[index] = (JavaValueNode) qt;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Prints the sub-nodes of this object.  See QueryTreeNode.java for\r
+        * how tree printing is supposed to work.\r
+        *\r
+        * @param depth         The depth of this node in the tree\r
+        */\r
+\r
+       public void printSubNodes(int depth)\r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       int     parm;\r
+\r
+                       super.printSubNodes(depth);\r
+                       if (methodParms != null)\r
+                       {\r
+                               for (parm = 0; parm < methodParms.length; parm++)\r
+                               {\r
+                                       if (methodParms[parm] != null)\r
+                                       {\r
+                                               printLabel(depth, "methodParms[" + parm + "] :");\r
+                                               methodParms[parm].treePrint(depth + 1);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\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 "methodName: " +\r
+                                       (methodName != null ? methodName : "null") + "\n" +\r
+                                       super.toString();\r
+               }\r
+               else\r
+               {\r
+                       return "";\r
+               }\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
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       final void bindParameters(\r
+               FromList fromList, SubqueryList subqueryList,\r
+               Vector  aggregateVector) \r
+                       throws StandardException\r
+       {\r
+               /* Bind the parameters */\r
+               if (methodParms != null)\r
+               {\r
+                       int             count = methodParms.length;\r
+\r
+                       // with a procedure call the signature\r
+                       // is preformed in StaticMethodCall from\r
+                       // the procedures signature.\r
+                       if (signature == null) \r
+                               signature = new JSQLType[ count ];\r
+\r
+                       for (int parm = 0; parm < count; parm++)\r
+                       {\r
+                               if (methodParms[parm] != null)\r
+                               {\r
+                                       methodParms[parm] =\r
+                                               methodParms[parm].bindExpression(\r
+                                                       fromList, subqueryList, aggregateVector);\r
+\r
+                                       if (routineInfo == null)\r
+                                               signature[ parm ] = methodParms[ parm ].getJSQLType();\r
+                    \r
+                    // prohibit LOB columns/types\r
+                    if (signature[parm] != null) {\r
+                        String type = signature[parm].getSQLType().getTypeId().getSQLTypeName();\r
+                        if (type.equals("BLOB") || type.equals("CLOB") || type.equals("NCLOB")) {\r
+                            throw StandardException.newException(SQLState.LOB_AS_METHOD_ARGUMENT_OR_RECEIVER);\r
+                        }\r
+                    }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Return whether or not all of the parameters to this node are\r
+        * QUERY_INVARIANT or CONSTANT.  This is useful for VTIs - a VTI is a candidate\r
+        * for materialization if all of its parameters are QUERY_INVARIANT or CONSTANT\r
+        *\r
+        * @return Whether or not all of the parameters to this node are QUERY_INVARIANT or CONSTANT\r
+        * @exception StandardException thrown on error\r
+        */\r
+        protected boolean areParametersQueryInvariant() throws StandardException\r
+        {\r
+               return (getVariantTypeOfParams() == Qualifier.QUERY_INVARIANT);\r
+        }\r
+\r
+       /**\r
+        * Build parameters for error message and throw the exception when there\r
+        * is no matching signature found.\r
+        *\r
+        * @param receiverTypeName      Type name for receiver\r
+        * @param parmTypeNames         Type names for parameters as object types\r
+        * @param primParmTypeNames     Type names for parameters as primitive types\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       void throwNoMethodFound(String receiverTypeName,\r
+                                                                         String[] parmTypeNames,\r
+                                                                         String[] primParmTypeNames)\r
+               throws StandardException\r
+       {\r
+               /* Put the parameter type names into a single string */\r
+               StringBuffer    parmTypes = new StringBuffer();\r
+               for (int i = 0; i < parmTypeNames.length; i++)\r
+               {\r
+                       if (i != 0)\r
+                               parmTypes.append(", ");\r
+                       /* RESOLVE - shouldn't be using hard coded strings for output */\r
+                       parmTypes.append( (parmTypeNames[i].length() != 0 ?\r
+                                                               parmTypeNames[i] :\r
+                                                               "UNTYPED"));\r
+                       if ((primParmTypeNames != null) &&\r
+                               ! primParmTypeNames[i].equals(parmTypeNames[i]))  // has primitive\r
+                               parmTypes.append("(" + primParmTypeNames[i] + ")");\r
+               }\r
+\r
+               throw StandardException.newException(SQLState.LANG_NO_METHOD_FOUND, \r
+                                                                                               receiverTypeName,\r
+                                                                                               methodName,\r
+                                                                                               parmTypes);\r
+       }\r
+\r
+       /**\r
+        * Preprocess an expression tree.  We do a number of transformations\r
+        * here (including subqueries, IN lists, LIKE and BETWEEN) plus\r
+        * subquery flattening.\r
+        * NOTE: This is done before the outer ResultSetNode is preprocessed.\r
+        *\r
+        * @param       numTables                       Number of tables in the DML Statement\r
+        * @param       outerFromList           FromList from outer query block\r
+        * @param       outerSubqueryList       SubqueryList from outer query block\r
+        * @param       outerPredicateList      PredicateList from outer query block\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void preprocess(int numTables,\r
+                                                       FromList outerFromList,\r
+                                                       SubqueryList outerSubqueryList,\r
+                                                       PredicateList outerPredicateList) \r
+                                       throws StandardException\r
+       {\r
+               int     parm;\r
+\r
+               /* Preprocess the parameters */\r
+               if (methodParms != null)\r
+               {\r
+                       for (parm = 0; parm < methodParms.length; parm++)\r
+                       {\r
+                               if (methodParms[parm] != null)\r
+                               {\r
+                                       methodParms[parm].preprocess(numTables,\r
+                                                                                                outerFromList,\r
+                                                                                                outerSubqueryList,\r
+                                                                                                outerPredicateList);\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
+        * @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
+               int             param;\r
+\r
+               if (methodParms != null)\r
+               {\r
+                       for (param = 0; param < methodParms.length; param++)\r
+                       {\r
+                               if (methodParms[param] != null)\r
+                               {\r
+                                       pushable = methodParms[param].categorize(referencedTabs, simplePredsOnly) &&\r
+                                                          pushable;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               /* We need to push down method call.  Then the predicate can be used for start/stop\r
+                * key for index scan.  The fact that method call's cost is not predictable and can\r
+                * be expensive doesn't mean we shouldn't push it down. Beetle 4826.\r
+                */\r
+               return pushable;\r
+       }\r
+\r
+       /**\r
+        * Remap all ColumnReferences in this tree to be clones of the\r
+        * underlying expression.\r
+        *\r
+        * @return JavaValueNode                        The remapped expression tree.\r
+        *\r
+        * @exception StandardException                 Thrown on error\r
+        */\r
+       public JavaValueNode remapColumnReferencesToExpressions()\r
+               throws StandardException\r
+       {\r
+               int     param;\r
+\r
+               if (methodParms != null)\r
+               {\r
+                       for (param = 0; param < methodParms.length; param++)\r
+                       {\r
+                               if (methodParms[param] != null)\r
+                               {\r
+                                       methodParms[param] =\r
+                                               methodParms[param].remapColumnReferencesToExpressions();\r
+                               }\r
+                       }\r
+               }\r
+               return this;\r
+       }\r
+\r
+       /**\r
+        * Generate the parameters to the given 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
+        * @return      Count of arguments to the method.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public  int generateParameters(ExpressionClassBuilder acb,\r
+                                                                                       MethodBuilder mb)\r
+                       throws StandardException\r
+       {\r
+               int                             param;\r
+\r
+               String[] expectedTypes = methodParameterTypes;\r
+\r
+               ClassInspector classInspector = getClassFactory().getClassInspector();\r
+\r
+               /* Generate the code for each user parameter, generating the appropriate\r
+                * cast when the passed type needs to get widened to the expected type.\r
+                */\r
+               for (param = 0; param < methodParms.length; param++)\r
+               {\r
+                       generateOneParameter( acb, mb, param );\r
+\r
+                       // type from the SQL-J expression\r
+                       String argumentType = getParameterTypeName( methodParms[param] );\r
+\r
+                       // type of the method\r
+                       String parameterType = expectedTypes[param];\r
+\r
+                       if (!parameterType.equals(argumentType))\r
+                       {\r
+                               // since we reached here through method resolution\r
+                               // casts are only required for primitive types.\r
+                               // In any other case the expression type must be assignable\r
+                               // to the parameter type.\r
+                               if (ClassInspector.primitiveType(parameterType)) {\r
+                                       mb.cast(parameterType);\r
+                               } else {\r
+\r
+                                       // for a prodcedure\r
+                                       if (routineInfo != null) {\r
+                                               continue; // probably should be only for INOUT/OUT parameters.\r
+                                       }\r
+\r
+                                       if (SanityManager.DEBUG) {\r
+                                               SanityManager.ASSERT(classInspector.assignableTo(argumentType, parameterType),\r
+                                                       "Argument type " + argumentType + " is not assignable to parameter " + parameterType);\r
+                                       }\r
+\r
+                                       /*\r
+                                       ** Set the parameter type in case the argument type is narrower\r
+                                       ** than the parameter type.\r
+                                       */\r
+                                       mb.upCast(parameterType);\r
+\r
+                               }\r
+                       }\r
+\r
+               }\r
+\r
+               return methodParms.length;\r
+       }\r
+\r
+       static  public  String  getParameterTypeName( JavaValueNode param )\r
+               throws StandardException\r
+       {\r
+               String  argumentType;\r
+\r
+               // RESOLVE - shouldn't this logic be inside JavaValueNode ??\r
+               // I.e. once the value is primitive then its java type name is its\r
+               // primitive type name.\r
+               if (param.isPrimitiveType()) { argumentType = param.getPrimitiveTypeName(); }\r
+               else { argumentType = param.getJavaTypeName(); }\r
+\r
+               return  argumentType;\r
+       }\r
+\r
+       /**\r
+        * Generate one parameter to the given method call. This method is overriden by\r
+        * RepStaticMethodCallNode.\r
+        *\r
+        * @param acb                           The ExpressionClassBuilder for the class we're generating\r
+        * @param mb the method the expression will go into\r
+        * @param parameterNumber       Identifies which parameter to generate. 0 based.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public  void generateOneParameter(ExpressionClassBuilder acb,\r
+                                                                                       MethodBuilder mb,\r
+                                                                                       int parameterNumber )\r
+                       throws StandardException\r
+       {\r
+               methodParms[parameterNumber].generateExpression(acb, mb);\r
+       }\r
+\r
+       /**\r
+        * Set the appropriate type information for a null passed as a parameter.\r
+        * This method is called after method resolution, when a signature was\r
+        * successfully matched.\r
+        *\r
+        * @param parmTypeNames String[] with the java type names for the parameters\r
+        *        as declared by the method\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void     setNullParameterInfo(String[] parmTypeNames)\r
+                       throws StandardException\r
+       {\r
+               for (int i = 0; i < methodParms.length; i++)\r
+               {\r
+                       /* null parameters are represented by a java type name of "" */\r
+                       if (methodParms[i].getJavaTypeName().equals(""))\r
+                       {               \r
+                               /* Set the type information in the null constant node */\r
+                               DataTypeDescriptor dts = DataTypeDescriptor.getSQLDataTypeDescriptor(parmTypeNames[i]);\r
+                               ((SQLToJavaValueNode)methodParms[i]).value.setType(dts);\r
+\r
+                               /* Set the correct java type name */\r
+                               methodParms[i].setJavaTypeName(parmTypeNames[i]);\r
+                               signature[i] = methodParms[i].getJSQLType();\r
+                       }\r
+               }\r
+       }\r
+\r
+       protected void resolveMethodCall(String javaClassName,\r
+                                                                        boolean staticMethod) \r
+                               throws StandardException\r
+       {\r
+               // only allow direct method calls through routines and internal SQL.\r
+               if (routineInfo == null && !internalCall)\r
+               {\r
+                       // See if we are being executed in an internal context\r
+                       if ((getCompilerContext().getReliability() & CompilerContext.INTERNAL_SQL_ILLEGAL) != 0) {\r
+                               throw StandardException.newException(SQLState.LANG_SYNTAX_ERROR,  javaClassName + (staticMethod ? "::" : ".") + methodName);\r
+                       }\r
+               }\r
+\r
+               int                     count = signature.length;\r
+\r
+               ClassInspector classInspector = getClassFactory().getClassInspector();\r
+\r
+               \r
+               String[]                parmTypeNames;\r
+               String[]                primParmTypeNames = null;\r
+               boolean[]               isParam = getIsParam();\r
+\r
+               boolean hasDynamicResultSets = (routineInfo != null) && (count != 0) && (count != methodParms.length);\r
+\r
+        /*\r
+        ** Find the matching method that is public.\r
+        */\r
+\r
+               int signatureOffset = methodName.indexOf('(');\r
+               \r
+            // support Java signatures by checking if the method name contains a '('\r
+            if (signatureOffset != -1) {\r
+                       parmTypeNames = parseValidateSignature(methodName, signatureOffset, hasDynamicResultSets);\r
+               methodName = methodName.substring(0, signatureOffset);\r
+               \r
+               // If the signature is specified then Derby resolves to exactly\r
+               // that method. Setting this flag to false disables the method\r
+               // resolution from automatically optionally repeating the last\r
+               // parameter as needed.\r
+               hasDynamicResultSets = false;\r
+                \r
+            }\r
+            else\r
+            {\r
+               parmTypeNames = getObjectSignature();\r
+            }\r
+        try\r
+        {                              \r
+                method = classInspector.findPublicMethod(javaClassName,\r
+                                                    methodName,\r
+                                                    parmTypeNames,\r
+                                                    null,\r
+                                                    isParam,\r
+                                                    staticMethod,\r
+                                                    hasDynamicResultSets);\r
+\r
+\r
+                // DB2 LUW does not support Java object types for SMALLINT, INTEGER, BIGINT, REAL, DOUBLE\r
+                // and these are the only types that can map to a primitive or an object type according\r
+                // to SQL part 13. So we never have a second chance match.\r
+                // Also if the DDL specified a signature, then no alternate resolution\r
+                if (signatureOffset == -1 && routineInfo == null) {\r
+\r
+                    /* If no match, then retry with combinations of object and\r
+                     * primitive types.\r
+                     */\r
+                    if (method == null)\r
+                    {\r
+                        primParmTypeNames = getPrimitiveSignature(false);\r
+\r
+                        method = classInspector.findPublicMethod(javaClassName,\r
+                                                    methodName,\r
+                                                    parmTypeNames,\r
+                                                    primParmTypeNames,\r
+                                                    isParam,\r
+                                                    staticMethod,\r
+                                                    hasDynamicResultSets);\r
+                    }\r
+                }\r
+        }\r
+        catch (ClassNotFoundException e)\r
+        {\r
+            /*\r
+            ** If one of the classes couldn't be found, just act like the\r
+            ** method couldn't be found.  The error lists all the class names,\r
+            ** which should give the user enough info to diagnose the problem.\r
+            */\r
+            method = null;\r
+        }\r
+               /* Throw exception if no matching signature found */\r
+               if (method == null)\r
+               {\r
+                       throwNoMethodFound(javaClassName, parmTypeNames, primParmTypeNames);\r
+               }\r
+\r
+               String  typeName = classInspector.getType(method);\r
+               actualMethodReturnType = typeName;\r
+\r
+               if (routineInfo == null) {\r
+\r
+                       /* void methods are only okay for CALL Statements */\r
+                       if (typeName.equals("void"))\r
+                       {\r
+                               if (!forCallStatement)\r
+                                       throw StandardException.newException(SQLState.LANG_VOID_METHOD_CALL);\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       String promoteName = null;\r
+                       TypeDescriptor returnType = routineInfo.getReturnType();\r
+                       String requiredType;\r
+                       if (returnType == null)\r
+                       {\r
+                               // must have a void method for a procedure call.\r
+                               requiredType = "void";\r
+                       }\r
+                       else\r
+                       {\r
+                               TypeId returnTypeId = TypeId.getBuiltInTypeId(returnType.getJDBCTypeId());\r
+\r
+                               requiredType = returnTypeId.getCorrespondingJavaTypeName();\r
+\r
+                               if (!requiredType.equals(typeName)) {\r
+                                       switch (returnType.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
+                                               TypeCompiler tc = getTypeCompiler(returnTypeId);\r
+                                               requiredType = tc.getCorrespondingPrimitiveTypeName();\r
+                                               if (!routineInfo.calledOnNullInput() && \r
+                                                               routineInfo.getParameterCount() != 0) {\r
+                                                       promoteName = returnTypeId.getCorrespondingJavaTypeName();\r
+                                               }\r
+                                               \r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       if (!requiredType.equals(typeName))\r
+                       {\r
+                               throwNoMethodFound(requiredType + " " + javaClassName, parmTypeNames, primParmTypeNames);\r
+                       }\r
+\r
+                       // for a returns null on null input with a primitive\r
+                       // type we need to promote to an object so we can return null.\r
+                       if (promoteName != null)\r
+                               typeName = promoteName;\r
+                       //propogate collation type from RoutineAliasInfo to\r
+                       // MethodCallNode DERBY-2972\r
+                        if (routineInfo.getReturnType() != null)\r
+                            setCollationType(routineInfo.getReturnType().getCollationType());     \r
+                }\r
+               setJavaTypeName( typeName );\r
+                \r
+               methodParameterTypes = classInspector.getParameterTypes(method);\r
+\r
+               for (int i = 0; i < methodParameterTypes.length; i++)\r
+               {\r
+                       String methodParameter = methodParameterTypes[i];\r
+\r
+                       if (routineInfo != null) {\r
+                               if (i < routineInfo.getParameterCount()) {\r
+                                       int parameterMode = routineInfo.getParameterModes()[i];\r
+\r
+                                       switch (parameterMode) {\r
+                                       case JDBC30Translation.PARAMETER_MODE_IN:\r
+                                               break;\r
+                                       case JDBC30Translation.PARAMETER_MODE_IN_OUT:\r
+                                               // we need to see if the type of the array is\r
+                                               // primitive, not the array itself.\r
+                                               methodParameter = methodParameter.substring(0, methodParameter.length() - 2);\r
+                                               break;\r
+\r
+                                       case JDBC30Translation.PARAMETER_MODE_OUT:\r
+                                               // value is not obtained *from* parameter.\r
+                                               continue;\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       if (ClassInspector.primitiveType(methodParameter))\r
+                               methodParms[i].castToPrimitive(true);\r
+               }\r
+\r
+               /* Set type info for any null parameters */\r
+               if ( someParametersAreNull() )\r
+               {\r
+                       setNullParameterInfo(methodParameterTypes);\r
+               }\r
+\r
+\r
+    \r
+               /* bug 4450 - if the callable statement is ? = call form, generate the metadata\r
+               infor for the return parameter. We don't really need that info in order to\r
+               execute the callable statement. But with jdbc3.0, this information should be\r
+               made available for return parameter through ParameterMetaData class.\r
+               Parser sets a flag in compilercontext if ? = call. If the flag is set,\r
+               we generate the metadata info for the return parameter and reset the flag\r
+               in the compilercontext for future call statements*/\r
+               DataTypeDescriptor dts = DataTypeDescriptor.getSQLDataTypeDescriptor(typeName);\r
+               if (getCompilerContext().getReturnParameterFlag()) {\r
+                       getCompilerContext().getParameterTypes()[0] = dts;\r
+               }\r
+  }\r
+       \r
+       /**\r
+        * Parse the user supplied signature for a method and validate\r
+        * it, need to match the number of parameters passed in and match\r
+        * the valid types for the parameter.\r
+        * @param offset Character offset of first paren\r
+        * @param hasDynamicResultSets Can ResultSet[] parameters be specified.\r
+        * @return The valid array of types for resolution.\r
+        * @throws StandardException\r
+        */\r
+       private String[] parseValidateSignature(String externalName, int offset,\r
+                       boolean hasDynamicResultSets)\r
+               throws StandardException\r
+       {\r
+               int siglen = externalName.length();\r
+\r
+               // Ensure the opening paren is not the last\r
+               // character and that the last character is a close paren\r
+               if (((offset + 1) == siglen)\r
+                       || (externalName.charAt(siglen - 1) != ')'))\r
+                       throw StandardException.newException(SQLState.SQLJ_SIGNATURE_INVALID); // invalid\r
+               \r
+        StringTokenizer st = new StringTokenizer(externalName.substring(offset + 1, siglen - 1), ",", true);\r
+        \r
+        String[] signatureTypes = new String[signature.length];\r
+        int count;\r
+        boolean seenClass = false;\r
+        for (count = 0; st.hasMoreTokens();)\r
+        {\r
+               String type = st.nextToken().trim();\r
\r
+               // check sequence is <class><comma>class> etc.\r
+               if (",".equals(type))\r
+               {\r
+                       if (!seenClass)\r
+                               throw StandardException.newException(SQLState.SQLJ_SIGNATURE_INVALID); // invalid\r
+                       seenClass = false;\r
+                       continue;\r
+               }\r
+               else\r
+               {\r
+                       if (type.length() == 0)\r
+                               throw StandardException.newException(SQLState.SQLJ_SIGNATURE_INVALID); // invalid\r
+                       seenClass = true;\r
+                       count++;\r
+               }\r
+                                                          \r
+               if (count > signature.length)\r
+               {\r
+                       if (hasDynamicResultSets)\r
+                       {\r
+                               // Allow any number of dynamic result set holders\r
+                               // but they must match the exact type.\r
+                               String rsType = signature[signature.length - 1].getSQLType().\r
+                                               getTypeId().getCorrespondingJavaTypeName();\r
+                               \r
+                               if (!type.equals(rsType))\r
+                                       throw StandardException.newException(SQLState.LANG_DATA_TYPE_GET_MISMATCH, \r
+                                               type, rsType);\r
+\r
+                               if (signatureTypes.length == signature.length)\r
+                               {\r
+                                       // expand once\r
+                                       String[] sigs = new String[st.countTokens()];\r
+                                       System.arraycopy(signatureTypes, 0, sigs, 0, signatureTypes.length);\r
+                                       signatureTypes = sigs;\r
+                               }\r
+                               \r
+                       signatureTypes[count - 1] = type;\r
+                       continue;\r
+                               \r
+                       }\r
+                       throw StandardException.newException(SQLState.SQLJ_SIGNATURE_PARAMETER_COUNT, \r
+                                       Integer.toString(count),\r
+                                       Integer.toString(signature.length)); // too many types\r
+               }\r
+\r
+                       \r
+               TypeId  paramTypeId = signature[count - 1].getSQLType().getTypeId();\r
+                               \r
+               // Does it match the object name\r
+               if (type.equals(paramTypeId.getCorrespondingJavaTypeName()))\r
+               {\r
+                       signatureTypes[count - 1] = type;\r
+                       continue;\r
+               }\r
+       \r
+               // how about the primitive name\r
+                       if ((paramTypeId.isNumericTypeId() && !paramTypeId.isDecimalTypeId())\r
+                                       || paramTypeId.isBooleanTypeId())\r
+                       {\r
+                               TypeCompiler tc = getTypeCompiler(paramTypeId);\r
+                               if (type.equals(tc.getCorrespondingPrimitiveTypeName()))\r
+                               {\r
+                               signatureTypes[count - 1] = type;\r
+                               continue;                                       \r
+                               }\r
+                       }\r
+               throw StandardException.newException(SQLState.LANG_DATA_TYPE_GET_MISMATCH, \r
+                                       type, paramTypeId.getSQLTypeName()); // type conversion error\r
+        }\r
+        \r
+        // Did signature end with trailing comma?\r
+        if (count != 0 && !seenClass)\r
+               throw StandardException.newException(SQLState.SQLJ_SIGNATURE_INVALID); // invalid\r
+        \r
+        if (count < signatureTypes.length)\r
+        {\r
+               if (hasDynamicResultSets)\r
+               {\r
+                       // we can tolerate a count of one less than the\r
+                       // expected count, which means the procedure is declared\r
+                       // to have dynamic result sets, but the explict signature\r
+                       // doesn't have any ResultSet[] types.\r
+                       // So accept, and procedure will automatically have 0\r
+                       // dynamic results at runtime\r
+                       if (count == (signature.length - 1))\r
+                       {\r
+                               String[] sigs = new String[count];\r
+                               System.arraycopy(signatureTypes, 0, sigs, 0, count);\r
+                               return sigs;\r
+                       }\r
+               }\r
+                       throw StandardException.newException(SQLState.SQLJ_SIGNATURE_PARAMETER_COUNT, \r
+                               Integer.toString(count),\r
+                               Integer.toString(signature.length)); // too few types\r
+        }\r
+\r
+        return signatureTypes;\r
+       }\r
+\r
+       /**\r
+         *     Return true if some parameters are null, false otherwise.\r
+         */\r
+       protected       boolean someParametersAreNull()\r
+       {\r
+               int             count = signature.length;\r
+               \r
+               for ( int ictr = 0; ictr < count; ictr++ )\r
+               {\r
+                       if ( signature[ictr] == null )\r
+                       {\r
+                               return true;\r
+                       }\r
+               }\r
+\r
+               return false;\r
+       }\r
+\r
+       /**\r
+         *     Build an array of names of the argument types. These types are biased toward\r
+         *     Java objects. That is, if an argument is of SQLType, then we map it to the\r
+         *     corresponding Java synonym class (e.g., SQLINT is mapped to 'java.lang.Integer').\r
+         *\r
+         *\r
+         *     @return array of type names\r
+         *\r
+         * @exception StandardException                Thrown on error\r
+         */\r
+       protected       String[]        getObjectSignature( )\r
+               throws StandardException\r
+       {\r
+               int             count = signature.length;\r
+               String  parmTypeNames[] = new String[ count ];\r
+\r
+               for ( int i = 0; i < count; i++ ) { parmTypeNames[i] = getObjectTypeName( signature[ i ] ); }\r
+\r
+               return parmTypeNames;\r
+       }\r
+\r
+       /**\r
+        * Build an array of booleans denoting whether or not a given method\r
+        * parameter is a ?.\r
+        *\r
+        * @return array of booleans denoting wheter or not a given method\r
+        * parameter is a ?.\r
+        */\r
+       protected boolean[] getIsParam()\r
+       {\r
+               if (methodParms == null)\r
+               {\r
+                       return new boolean[0];\r
+               }\r
+               \r
+               boolean[] isParam = new boolean[methodParms.length];\r
+\r
+               for (int index = 0; index < methodParms.length; index++)\r
+               {\r
+                       if (methodParms[index] instanceof SQLToJavaValueNode)\r
+                       {\r
+                               SQLToJavaValueNode stjvn = (SQLToJavaValueNode) methodParms[index];\r
+                               if (stjvn.value.requiresTypeFromContext())\r
+                               {\r
+                                       isParam[index] = true;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return isParam;\r
+       }\r
+\r
+       private String  getObjectTypeName( JSQLType jsqlType )\r
+               throws StandardException\r
+       {\r
+               if ( jsqlType != null )\r
+               {\r
+                       switch( jsqlType.getCategory() )\r
+                       {\r
+                           case JSQLType.SQLTYPE: \r
+\r
+                                       TypeId  ctid = mapToTypeID( jsqlType );\r
+\r
+                                       if ( ctid == null ) { return null; }\r
+                                       else {\r
+                                               // DB2 LUW does not support Java object types for SMALLINT, INTEGER, BIGINT, REAL, DOUBLE\r
+                                               // and these are the only types that can map to a primitive or an object type according\r
+                                               // to SQL part 13. So always map to the primitive type. We can not use the getPrimitiveSignature()\r
+                                               // as it (incorrectly but historically always has) maps a DECIMAL to a double. \r
+\r
+                                               switch (ctid.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
+                                                       if (routineInfo != null) {\r
+                                                               TypeCompiler tc = getTypeCompiler(ctid);\r
+                                                               return tc.getCorrespondingPrimitiveTypeName();\r
+                                                       }\r
+                                                       // fall through\r
+                                               default:\r
+                                                       return ctid.getCorrespondingJavaTypeName();\r
+                                               }\r
+                                       }\r
+\r
+                       case JSQLType.JAVA_CLASS: return jsqlType.getJavaClassName();\r
+\r
+                       case JSQLType.JAVA_PRIMITIVE: return JSQLType.primitiveNames[ jsqlType.getPrimitiveKind() ];\r
+\r
+                       default:\r
+\r
+                                       if (SanityManager.DEBUG)\r
+                                       { SanityManager.THROWASSERT( "Unknown JSQLType: " + jsqlType ); }\r
+\r
+                       }\r
+               }\r
+\r
+               return "";\r
+       }\r
+\r
+       String[]        getPrimitiveSignature( boolean castToPrimitiveAsNecessary )\r
+               throws StandardException\r
+       {\r
+               int                                     count = signature.length;\r
+               String[]                        primParmTypeNames = new String[ count ];\r
+               JSQLType                        jsqlType;\r
+\r
+               for (int i = 0; i < count; i++)\r
+               {\r
+                       jsqlType = signature[ i ];\r
+\r
+                       if ( jsqlType == null ) { primParmTypeNames[i] = ""; }\r
+                       else\r
+                       {\r
+                               switch( jsqlType.getCategory() )\r
+                           {\r
+                               case JSQLType.SQLTYPE:\r
+\r
+                                               if ((procedurePrimitiveArrayType != null)\r
+                                                       && (i < procedurePrimitiveArrayType.length)\r
+                                                       && (procedurePrimitiveArrayType[i] != null)) {\r
+\r
+                                                       primParmTypeNames[i] = procedurePrimitiveArrayType[i];\r
+\r
+                                               } else {\r
+\r
+\r
+                                                       TypeId  ctid = mapToTypeID( jsqlType );\r
+\r
+                                                       if ((ctid.isNumericTypeId() && !ctid.isDecimalTypeId()) || ctid.isBooleanTypeId())\r
+                                                       {\r
+                                                               TypeCompiler tc = getTypeCompiler(ctid);\r
+                                                               primParmTypeNames[i] = tc.getCorrespondingPrimitiveTypeName();\r
+                                                               if ( castToPrimitiveAsNecessary) { methodParms[i].castToPrimitive(true); }\r
+                                                       }\r
+                                                       else { primParmTypeNames[i] = ctid.getCorrespondingJavaTypeName(); }\r
+                                               }\r
+\r
+                                               break;\r
+\r
+                           case JSQLType.JAVA_CLASS:\r
+\r
+                                               primParmTypeNames[i] = jsqlType.getJavaClassName();\r
+                                               break;\r
+\r
+                           case JSQLType.JAVA_PRIMITIVE:\r
+\r
+                                               primParmTypeNames[i] = JSQLType.primitiveNames[ jsqlType.getPrimitiveKind() ];\r
+                                               if ( castToPrimitiveAsNecessary) { methodParms[i].castToPrimitive(true); }\r
+                                               break;\r
+\r
+                           default:\r
+\r
+                                               if (SanityManager.DEBUG)\r
+                                                       { SanityManager.THROWASSERT( "Unknown JSQLType: " + jsqlType ); }\r
+\r
+                               }       // end switch\r
+\r
+                       }               // end if\r
+\r
+               }                       // end for\r
+\r
+               return primParmTypeNames;\r
+       }\r
+\r
+       /**\r
+        * Return the variant type for the underlying expression.\r
+        * The variant type can be:\r
+        *              VARIANT                         - variant within a scan\r
+        *                                                        (non-static field access)\r
+        *              SCAN_INVARIANT          - invariant within a scan\r
+        *                                                        (column references from outer tables)\r
+        *              QUERY_INVARIANT         - invariant within the life of a query\r
+        *                                                        (constant expressions)\r
+        *\r
+        * @return      The variant type for the underlying expression.\r
+        */\r
+       protected int getOrderableVariantType() throws StandardException\r
+       {\r
+               // beetle 4880. We return the most variant type of the parameters. If no\r
+               // params then query-invariant. This makes more sense, and we can evaluate\r
+               // only once per query (good for performance) because method call could be\r
+               // expensive.  And if we push down method qualifier to store, language\r
+               // can pre-evaluate the method call.  This avoids letting store evaluate\r
+               // the method while holding page latch, causing deadlock.\r
+\r
+               return getVariantTypeOfParams();\r
+       }\r
+\r
+       private int getVariantTypeOfParams() throws StandardException\r
+       {\r
+               int variance = Qualifier.QUERY_INVARIANT;\r
+\r
+               if (methodParms != null)\r
+               {\r
+                       for (int parm = 0; parm < methodParms.length; parm++)\r
+                       {\r
+                               if (methodParms[parm] != null)\r
+                               {\r
+                                       int paramVariantType =\r
+                                               methodParms[parm].getOrderableVariantType();\r
+                                       if (paramVariantType < variance)        //return the most variant type\r
+                                               variance = paramVariantType;\r
+                               }\r
+                               else\r
+                               {\r
+                                       variance = Qualifier.VARIANT;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return variance;\r
+       }\r
+\r
+\r
+       /////////////////////////////////////////////////////////////////////\r
+       //\r
+       //      ACCESSORS\r
+       //\r
+       /////////////////////////////////////////////////////////////////////\r
+       /**\r
+        * Get the method parameters.\r
+        * \r
+        * @return      The method parameters\r
+        */\r
+       public JavaValueNode[]  getMethodParms()\r
+       {\r
+               return methodParms;\r
+       }\r
+\r
+       /**\r
+        * Accept a visitor, and call v.visit()\r
+        * on child nodes as necessary.  \r
+        * \r
+        * @param v the visitor\r
+        *\r
+        * @exception StandardException on error\r
+        */\r
+       public Visitable accept(Visitor v) \r
+               throws StandardException\r
+       {\r
+               Visitable               returnNode = v.visit(this);\r
+\r
+               if (v.skipChildren(this))\r
+               {\r
+                       return returnNode;\r
+               }\r
+\r
+               for (int parm = 0; \r
+                       !v.stopTraversal() && parm < methodParms.length; \r
+                       parm++)\r
+               {\r
+                       if (methodParms[parm] != null)\r
+                       {\r
+                               methodParms[parm] = (JavaValueNode)methodParms[parm].accept(v);\r
+                       }\r
+               }\r
+\r
+               return returnNode;\r
+       }\r
+}\r