Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / impl / sql / compile / CallStatementNode.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/compile/CallStatementNode.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/compile/CallStatementNode.java
new file mode 100644 (file)
index 0000000..f2183e9
--- /dev/null
@@ -0,0 +1,325 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.CallStatementNode\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 java.lang.reflect.Modifier;\r
+\r
+import org.apache.derby.catalog.types.RoutineAliasInfo;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.ClassName;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.sql.ResultDescription;\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+import org.apache.derby.iapi.sql.compile.CompilerContext;\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.conn.Authorizer;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+\r
+/**\r
+ * An CallStatementNode represents a CALL <procedure> statement.\r
+ * It is the top node of the query tree for that statement.\r
+ * A procedure call is very simple.\r
+ * \r
+ * CALL [<schema>.]<procedure>(<args>)\r
+ * \r
+ * <args> are either constants or parameter markers.\r
+ * This implementation assumes that no subqueries or aggregates\r
+ * can be in the argument list.\r
+ * \r
+ * A procedure is always represented by a MethodCallNode.\r
+ *\r
+ */\r
+public class CallStatementNode extends DMLStatementNode\r
+{      \r
+       /**\r
+        * The method call for the Java procedure. Guaranteed to be\r
+        * a JavaToSQLValueNode wrapping a MethodCallNode by checks\r
+        * in the parser.\r
+        */\r
+       private JavaToSQLValueNode      methodCall;\r
+\r
+\r
+       /**\r
+        * Initializer for a CallStatementNode.\r
+        *\r
+        * @param methodCall            The expression to "call"\r
+        */\r
+\r
+       public void init(Object methodCall)\r
+       {\r
+               super.init(null);\r
+               this.methodCall = (JavaToSQLValueNode) methodCall;\r
+               this.methodCall.getJavaValueNode().markForCallStatement();\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 "CALL " + methodCall.toString() + "\n" +\r
+                               super.toString();\r
+               }\r
+               else\r
+               {\r
+                       return "";\r
+               }\r
+       }\r
+\r
+       public String statementToString()\r
+       {\r
+               return "CALL";\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
+                       super.printSubNodes(depth);\r
+\r
+                       if (methodCall != null)\r
+                       {\r
+                               printLabel(depth, "methodCall: ");\r
+                               methodCall.treePrint(depth + 1);\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Bind this UpdateNode.  This means looking up tables and columns and\r
+        * getting their types, and figuring out the result types of all\r
+        * expressions, as well as doing view resolution, permissions checking,\r
+        * etc.\r
+        * <p>\r
+        * Binding an update will also massage the tree so that\r
+        * the ResultSetNode has a single column, the RID.\r
+        *\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public void bindStatement() throws StandardException\r
+       {\r
+               DataDictionary dd = getDataDictionary();\r
+\r
+               if (SanityManager.DEBUG)\r
+                       SanityManager.ASSERT((dd != null), "Failed to get data dictionary");\r
+\r
+               getCompilerContext().pushCurrentPrivType(getPrivType());\r
+               methodCall = (JavaToSQLValueNode) methodCall.bindExpression(\r
+                                                       (FromList) getNodeFactory().getNode(\r
+                                                               C_NodeTypes.FROM_LIST,\r
+                                                               getNodeFactory().doJoinOrderOptimization(),\r
+                                                               getContextManager()), \r
+                                                       null,\r
+                                                       null);\r
+\r
+               // Disallow creation of BEFORE triggers which contain calls to \r
+               // procedures that modify SQL data. \r
+               checkReliability();\r
+\r
+               getCompilerContext().popCurrentPrivType();\r
+       }\r
+\r
+       /**\r
+        * Optimize a DML statement (which is the only type of statement that\r
+        * should need optimizing, I think). This method over-rides the one\r
+        * in QueryTreeNode.\r
+        *\r
+        * This method takes a bound tree, and returns an optimized tree.\r
+        * It annotates the bound tree rather than creating an entirely\r
+        * new tree.\r
+        *\r
+        * Throws an exception if the tree is not bound, or if the binding\r
+        * is out of date.\r
+        *\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public void optimizeStatement() throws StandardException\r
+       {\r
+               DataDictionary dd = getDataDictionary();\r
+\r
+               if (SanityManager.DEBUG)\r
+               SanityManager.ASSERT((dd != null), "Failed to get data dictionary");\r
+\r
+               /* Preprocess the method call tree */\r
+               methodCall = (JavaToSQLValueNode) methodCall.preprocess(\r
+                                                               getCompilerContext().getNumTables(),\r
+                                                               (FromList) getNodeFactory().getNode(\r
+                                                                       C_NodeTypes.FROM_LIST,\r
+                                                                       getNodeFactory().doJoinOrderOptimization(),\r
+                                                                       getContextManager()),\r
+                                                               (SubqueryList) null,\r
+                                                               (PredicateList) null);\r
+\r
+       }\r
+\r
+       /**\r
+        * Code generation for CallStatementNode.\r
+        * The generated code will contain:\r
+        *              o  A generated void method for the user's method call.\r
+        *\r
+        * @param acb   The ActivationClassBuilder for the class being built\r
+        * @param mb    The method for the execute() method to be built\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void generate(ActivationClassBuilder acb,\r
+                                                               MethodBuilder mb)\r
+                                                       throws StandardException\r
+       {\r
+               JavaValueNode           methodCallBody;\r
+\r
+               /* generate the parameters */\r
+               generateParameterValueSet(acb);\r
+\r
+               /* \r
+                * Skip over the JavaToSQLValueNode and call generate() for the JavaValueNode.\r
+                * (This skips over generated code which is unnecessary since we are throwing\r
+                * away any return value and which won't work with void methods.)\r
+                * generates:\r
+                *     <methodCall.generate(acb)>;\r
+                * and adds it to userExprFun\r
+                */\r
+               methodCallBody = methodCall.getJavaValueNode();\r
+\r
+               /*\r
+               ** Tell the method call that its return value (if any) will be\r
+               ** discarded.  This is so it doesn't generate the ?: operator\r
+               ** that would return null if the receiver is null.  This is\r
+               ** important because the ?: operator cannot be made into a statement.\r
+               */\r
+               methodCallBody.markReturnValueDiscarded();\r
+\r
+               // this sets up the method\r
+               // generates:\r
+               //      void userExprFun {\r
+               //     method_call(<args>);\r
+               //  }\r
+               //\r
+               //  An expression function is used to avoid reflection.\r
+               //  Since the arguments to a procedure are simple, this\r
+               // will be the only expression function and so it will\r
+               // be executed directly as e0.\r
+               MethodBuilder userExprFun = acb.newGeneratedFun("void", Modifier.PUBLIC);\r
+               userExprFun.addThrownException("java.lang.Exception");\r
+               methodCallBody.generate(acb, userExprFun);\r
+               userExprFun.endStatement();\r
+               userExprFun.methodReturn();\r
+               userExprFun.complete();\r
+\r
+               acb.pushGetResultSetFactoryExpression(mb);\r
+               acb.pushMethodReference(mb, userExprFun); // first arg\r
+               acb.pushThisAsActivation(mb); // arg 2\r
+               mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getCallStatementResultSet", ClassName.ResultSet, 2);\r
+       }\r
+\r
+       public ResultDescription makeResultDescription()\r
+       {\r
+               return null;\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
+               if (v.skipChildren(this))\r
+               {\r
+                       return v.visit(this);\r
+               }\r
+\r
+               Visitable returnNode = super.accept(v);\r
+\r
+               if (!v.stopTraversal())\r
+               {\r
+                       methodCall = (JavaToSQLValueNode) methodCall.accept(v);\r
+               }\r
+\r
+               return returnNode;\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
+       /**\r
+        * This method checks if the called procedure allows modification of SQL \r
+        * data. If yes, it cannot be compiled if the reliability is \r
+        * <code>CompilerContext.MODIFIES_SQL_DATA_PROCEDURE_ILLEGAL</code>. This \r
+        * reliability is set for BEFORE triggers in the create trigger node. This \r
+        * check thus disallows creation of BEFORE triggers which contain calls to \r
+        * procedures that modify SQL data in the trigger action statement.  \r
+        * \r
+        * @throws StandardException\r
+        */\r
+       private void checkReliability() throws StandardException {\r
+               if(getSQLAllowedInProcedure() == RoutineAliasInfo.MODIFIES_SQL_DATA &&\r
+                               getCompilerContext().getReliability() == CompilerContext.MODIFIES_SQL_DATA_PROCEDURE_ILLEGAL) \r
+                       throw StandardException.newException(SQLState.LANG_UNSUPPORTED_TRIGGER_PROC);\r
+       }\r
+       \r
+       /**\r
+        * This method checks the SQL allowed by the called procedure. This method \r
+        * should be called only after the procedure has been resolved.\r
+        * \r
+        * @return      SQL allowed by the procedure\r
+        */\r
+       private short getSQLAllowedInProcedure() {\r
+               RoutineAliasInfo routineInfo = ((MethodCallNode)methodCall.getJavaValueNode()).routineInfo;\r
+               \r
+               // If this method is called before the routine has been resolved, routineInfo will be null \r
+               if (SanityManager.DEBUG)\r
+                       SanityManager.ASSERT((routineInfo != null), "Failed to get routineInfo");\r
+\r
+               return routineInfo.getSQLAllowed();\r
+       }\r
+}\r