Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / compile / CoalesceFunctionNode.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/CoalesceFunctionNode.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/CoalesceFunctionNode.java
new file mode 100644 (file)
index 0000000..bcad7fb
--- /dev/null
@@ -0,0 +1,431 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.CoalesceFunctionNode\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.reference.ClassName;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\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.impl.sql.compile.ExpressionClassBuilder;\r
+\r
+import org.apache.derby.iapi.services.compiler.LocalField;\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+import org.apache.derby.iapi.sql.compile.Visitable;\r
+import org.apache.derby.iapi.sql.compile.Visitor;\r
+\r
+import java.lang.reflect.Modifier;\r
+\r
+import java.util.Vector;\r
+\r
+/**\r
+ * This node represents coalesce/value function which returns the first argument that is not null.\r
+ * The arguments are evaluated in the order in which they are specified, and the result of the\r
+ * function is the first argument that is not null. The result can be null only if all the arguments\r
+ * can be null. The selected argument is converted, if necessary, to the attributes of the result.\r
+ *\r
+ *\r
+ * SQL Reference Guide for DB2 has section titled "Rules for result data types" at the following url\r
+ * http://publib.boulder.ibm.com/infocenter/db2help/index.jsp?topic=/com.ibm.db2.udb.doc/admin/r0008480.htm\r
+\r
+ * I have constructed following table based on various tables and information under "Rules for result data types"\r
+ * This table has FOR BIT DATA TYPES broken out into separate columns for clarity\r
+ *\r
+ * Note that are few differences between Derby and DB2\r
+ * 1)there are few differences between what datatypes are consdiered compatible\r
+ * In DB2, CHAR FOR BIT DATA datatypes are compatible with CHAR datatypes\r
+ * ie in addition to following table, CHAR is compatible with CHAR FOR BIT DATA, VARCHAR FOR BIT DATA and LONG VARCHAR FOR BIT DATA\r
+ * ie in addition to following table, VARCHAR is compatible with CHAR FOR BIT DATA, VARCHAR FOR BIT DATA and LONG VARCHAR FOR BIT DATA\r
+ * ie in addition to following table, LONG VARCHAR is compatible with CHAR FOR BIT DATA, VARCHAR FOR BIT DATA and LONG VARCHAR FOR BIT DATA\r
+ * ie in addition to following table, CHAR FOR BIT DATA is compatible with DATE, TIME, TIMESTAMP\r
+ * ie in addition to following table, VARCHAR FOR BIT DATA is compatible with DATE, TIME, TIMESTAMP\r
+ *\r
+ * 2)few datatypes donot have matching precision in Derby and DB2\r
+ * In DB2, precision of TIME is 8. In Derby, precision of TIME is 0.\r
+ * In DB2, precision,scale of TIMESTAMP is 26,6. In Derby, precision of TIMESTAMP is 0,0.\r
+ * In DB2, precision of DOUBLE is 15. In Derby, precision of DOUBLE is 52.\r
+ * In DB2, precision of REAL is 23. In Derby, precision of REAL is 7.\r
+ * In DB2, precision calculation equation is incorrect when we have int and decimal arguments.\r
+ * The equation should be p=x+max(w-x,10) since precision of integer is 10 in both DB2 and Derby. Instead, DB2 has p=x+max(w-x,11) \r
+ *\r
+ * Types.             S  I  B  D  R  D  C  V  L  C  V  L  C  D  T  T  B\r
+ *                    M  N  I  E  E  O  H  A  O  H  A  O  L  A  I  I  L\r
+ *                    A  T  G  C  A  U  A  R  N  A  R  N  O  T  M  M  O\r
+ *                    L  E  I  I  L  B  R  C  G  R  C  G  B  E  E  E  B\r
+ *                    L  G  N  M     L     H  V  .  H  V           S\r
+ *                    I  E  T  A     E     A  A  B  A  A           T\r
+ *                    N  R     L           R  R  I  R  R           A\r
+ *                    T                       C  T  .  .           M\r
+ *                                            H     B  B           P\r
+ *                                            A     I  I\r
+ *                                            R     T   T\r
+ * SMALLINT         { "SMALLINT", "INTEGER", "BIGINT", "DECIMAL", "DOUBLE", "DOUBLE", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR" },\r
+ * INTEGER          { "INTEGER", "INTEGER", "BIGINT", "DECIMAL", "DOUBLE", "DOUBLE", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR" },\r
+ * BIGINT           { "BIGINT", "BIGINT", "BIGINT", "DECIMAL", "DOUBLE", "DOUBLE", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR" },\r
+ * DECIMAL          { "DECIMAL", "DECIMAL", "DECIMAL", "DECIMAL", "DOUBLE", "DOUBLE", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR" },\r
+ * REAL             { "DOUBLE", "DOUBLE", "DOUBLE", "DOUBLE", "REAL", "DOUBLE", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR" },\r
+ * DOUBLE           { "DOUBLE", "DOUBLE", "DOUBLE", "DOUBLE", "DOUBLE", "DOUBLE", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR" },\r
+ * CHAR             { "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "CHAR", "VARCHAR", "LONG VARCHAR", "ERROR", "ERROR", "ERROR", "CLOB", "DATE", "TIME", "TIMESTAMP", "ERROR" },\r
+ * VARCHAR          { "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "VARCHAR", "VARCHAR","LONG VARCHAR", "ERROR", "ERROR", "ERROR", "CLOB", "DATE", "TIME", "TIMESTAMP", "ERROR" },\r
+ * LONGVARCHAR      { "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "LONG VARCHAR", "LONG VARCHAR", "LONG VARCHAR", "ERROR", "ERROR", "ERROR", "CLOB", "ERROR", "ERROR", "ERROR", "ERROR" },\r
+ * CHAR FOR BIT     { "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "BIT", "BIT VARYING", "LONG BIT VARYING", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR" },\r
+ * VARCH. BIT       { "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "BIT VARYING", "BIT VARYING", "LONG BIT VARYING", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR" },\r
+ * LONGVAR. BIT     { "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "LONG BIT VARYING", "LONG BIT VARYING", "LONG BIT VARYING", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR" },\r
+ * CLOB             { "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "CLOB", "CLOB", "CLOB", "ERROR", "ERROR", "ERROR", "CLOB", "ERROR", "ERROR", "ERROR", "ERROR" },\r
+ * DATE             { "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "DATE", "DATE", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "DATE", "ERROR", "ERROR", "ERROR" },\r
+ * TIME             { "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "TIME", "TIME", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "TIME", "ERROR", "ERROR" },\r
+ * TIMESTAMP        { "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "TIMESTAMP", "TIMESTAMP", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "TIMESTAMP", "ERROR" },\r
+ * BLOB             { "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "ERROR", "BLOB" }\r
+ */\r
+\r
+public class CoalesceFunctionNode extends ValueNode\r
+{\r
+       String  functionName; //Are we here because of COALESCE function or VALUE function\r
+       ValueNodeList   argumentsList; //this is the list of arguments to the function. We are interested in the first not-null argument\r
+\r
+       /**\r
+        * The generated method will generate code to call coalesce on\r
+        * this non-parameter argument.\r
+        */\r
+       private int firstNonParameterNodeIdx = -1;\r
+\r
+       /**\r
+        * Initializer for a CalesceFunctionNode\r
+        *\r
+        * @param functionName  Tells if the function was called with name COALESCE or with name VALUE\r
+        * @param argumentsList The list of arguments to the coalesce/value function\r
+        */\r
+       public void init(Object functionName, Object argumentsList)\r
+       {\r
+               this.functionName = (String) functionName;\r
+               this.argumentsList = (ValueNodeList) argumentsList;\r
+       }\r
+\r
+       /**\r
+        * Binding this expression means setting the result DataTypeServices.\r
+        * In this case, the result type is based on the rules in the table listed earlier.\r
+        *\r
+        * @param fromList                      The FROM list for the statement.\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      The new top of the expression tree.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public ValueNode bindExpression(FromList fromList, SubqueryList subqueryList,\r
+                                                       Vector  aggregateVector)\r
+                                       throws StandardException\r
+       {\r
+               //bind all the arguments\r
+               argumentsList.bindExpression(fromList, subqueryList, aggregateVector);\r
+\r
+               //There should be more than one argument\r
+               if (argumentsList.size() < 2)\r
+                       throw StandardException.newException(SQLState.LANG_DB2_NUMBER_OF_ARGS_INVALID, functionName);\r
+\r
+               //check if all the arguments are parameters. If yes, then throw an exception\r
+               if (argumentsList.containsAllParameterNodes())\r
+                       throw StandardException.newException(SQLState.LANG_DB2_COALESCE_FUNCTION_ALL_PARAMS);\r
+\r
+               int argumentsListSize = argumentsList.size();\r
+               //find the first non-param argument. The generated method will generate code to call coalesce on this argument\r
+               for (int index = 0; index < argumentsListSize; index++)\r
+               {\r
+                       if (!(((ValueNode) argumentsList.elementAt(index)).requiresTypeFromContext()))\r
+                       {\r
+                               firstNonParameterNodeIdx = index;\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               //make sure these arguments are compatible to each other before coalesce can be allowed\r
+               for (int index = 0; index < argumentsListSize; index++)\r
+               {\r
+                       if (((ValueNode) argumentsList.elementAt(index)).requiresTypeFromContext()) //since we don't know the type of param, can't check for compatibility\r
+                               continue;\r
+                               argumentsList.compatible((ValueNode) argumentsList.elementAt(index));\r
+               }\r
+\r
+               //set the result type to the most dominant datatype in the arguments list and based on the table listed above\r
+               setType(argumentsList.getDominantTypeServices());\r
+\r
+               //set all the parameter types to the type of the result type\r
+               for (int index = 0; index < argumentsListSize; index++)\r
+               {\r
+                       if (((ValueNode) argumentsList.elementAt(index)).requiresTypeFromContext())\r
+                       {\r
+                               ((ValueNode)argumentsList.elementAt(index)).setType(getTypeServices());\r
+                               break;\r
+                       }\r
+               }\r
+               return this;\r
+       }\r
+\r
+       /**\r
+        * Do code generation for coalese/value\r
+        *\r
+        * @param acb   The ExpressionClassBuilder for the class we're generating\r
+        * @param mb    The method the expression will go into\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public void generateExpression(ExpressionClassBuilder acb,\r
+                                                                                       MethodBuilder mb)\r
+                                                                       throws StandardException\r
+       {\r
+               int                     argumentsListSize = argumentsList.size();\r
+               String          receiverType = ClassName.DataValueDescriptor;\r
+               String          argumentsListInterfaceType = ClassName.DataValueDescriptor + "[]";\r
+\r
+               // Generate the code to build the array\r
+               LocalField arrayField =\r
+                       acb.newFieldDeclaration(Modifier.PRIVATE, argumentsListInterfaceType);\r
+\r
+               /* The array gets created in the constructor.\r
+                * All constant elements in the array are initialized\r
+                * in the constructor.  \r
+                */\r
+               /* Assign the initializer to the DataValueDescriptor[] field */\r
+               MethodBuilder cb = acb.getConstructor();\r
+               cb.pushNewArray(ClassName.DataValueDescriptor, argumentsListSize);\r
+               cb.setField(arrayField);\r
+\r
+               /* Set the array elements that are constant */\r
+               int numConstants = 0;\r
+               MethodBuilder nonConstantMethod = null;\r
+               MethodBuilder currentConstMethod = cb;\r
+               for (int index = 0; index < argumentsListSize; index++)\r
+               {\r
+                       MethodBuilder setArrayMethod;\r
+       \r
+                       if (argumentsList.elementAt(index) instanceof ConstantNode)\r
+                       {\r
+                               numConstants++;\r
+               \r
+                               /*if too many statements are added  to a  method, \r
+                               *size of method can hit  65k limit, which will\r
+                               *lead to the class format errors at load time.\r
+                               *To avoid this problem, when number of statements added \r
+                               *to a method is > 2048, remaing statements are added to  a new function\r
+                               *and called from the function which created the function.\r
+                               *See Beetle 5135 or 4293 for further details on this type of problem.\r
+                               */\r
+                               if(currentConstMethod.statementNumHitLimit(1))\r
+                               {\r
+                                       MethodBuilder genConstantMethod = acb.newGeneratedFun("void", Modifier.PRIVATE);\r
+                                       currentConstMethod.pushThis();\r
+                                       currentConstMethod.callMethod(VMOpcode.INVOKEVIRTUAL,\r
+                                                                                                 (String) null, \r
+                                                                                                 genConstantMethod.getName(),\r
+                                                                                                 "void", 0);\r
+                                       //if it is a generate function, close the metod.\r
+                                       if(currentConstMethod != cb){\r
+                                               currentConstMethod.methodReturn();\r
+                                               currentConstMethod.complete();\r
+                                       }\r
+                                       currentConstMethod = genConstantMethod;\r
+                               }\r
+                               setArrayMethod = currentConstMethod;\r
+                       } else {\r
+                               if (nonConstantMethod == null)\r
+                                       nonConstantMethod = acb.newGeneratedFun("void", Modifier.PROTECTED);\r
+                               setArrayMethod = nonConstantMethod;\r
+\r
+                       }\r
+\r
+                       setArrayMethod.getField(arrayField); \r
+                       ((ValueNode) argumentsList.elementAt(index)).generateExpression(acb, setArrayMethod);\r
+                       setArrayMethod.upCast(receiverType);\r
+                       setArrayMethod.setArrayElement(index);\r
+               }\r
+\r
+               //if a generated function was created to reduce the size of the methods close the functions.\r
+               if(currentConstMethod != cb){\r
+                       currentConstMethod.methodReturn();\r
+                       currentConstMethod.complete();\r
+               }\r
+\r
+               if (nonConstantMethod != null) {\r
+                       nonConstantMethod.methodReturn();\r
+                       nonConstantMethod.complete();\r
+                       mb.pushThis();\r
+                       mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, nonConstantMethod.getName(), "void", 0);\r
+               }\r
+\r
+               /*\r
+               **  Call the method for coalesce/value function.\r
+               **      First generate following\r
+               **      <first non-param argument in the list>.method(<all the arguments>, <resultType>)\r
+               **      Next, if we are dealing with result type that is variable length, then generate a call to setWidth.\r
+               */\r
+\r
+               // coalesce will be called on this non-parameter argument\r
+               ((ValueNode) argumentsList.elementAt(firstNonParameterNodeIdx)).\r
+                       generateExpression(acb, mb);\r
+\r
+               mb.upCast(ClassName.DataValueDescriptor);\r
+\r
+               mb.getField(arrayField); // first arg to the coalesce function\r
+\r
+               //Following is for the second arg. This arg will be used to pass the return value.\r
+               //COALESCE method expects this to be initialized to NULL SQLxxx type object.\r
+               LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, receiverType);\r
+               acb.generateNull(mb, getTypeCompiler(), getTypeServices().getCollationType());\r
+               mb.upCast(ClassName.DataValueDescriptor);\r
+               mb.putField(field);\r
+\r
+               mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, "coalesce", receiverType, 2);\r
+               if (getTypeId().variableLength())//since result type is variable length, generate setWidth code.\r
+               {\r
+                       boolean isNumber = getTypeId().isNumericTypeId();\r
+                       // to leave the DataValueDescriptor value on the stack, since setWidth is void\r
+                       mb.dup();\r
+\r
+                       mb.push(isNumber ? getTypeServices().getPrecision() : getTypeServices().getMaximumWidth());\r
+                       mb.push(getTypeServices().getScale());\r
+                       mb.push(true);\r
+                       mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue, "setWidth", "void", 3);\r
+               }\r
+       }\r
+\r
+       /*\r
+               print the non-node subfields\r
+        */\r
+       public String toString() \r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       return super.toString()+functionName+"("+argumentsList+")\n";\r
+               }\r
+               else\r
+               {\r
+                       return "";\r
+               }\r
+       }\r
+        \r
+       /**\r
+        * {@inheritDoc}\r
+        */\r
+       protected boolean isEquivalent(ValueNode o) throws StandardException\r
+       {\r
+               if (!isSameNodeType(o))\r
+               {\r
+                       return false;\r
+               }\r
+               \r
+               CoalesceFunctionNode other = (CoalesceFunctionNode)o;\r
+               if (other.argumentsList.size() != argumentsList.size())\r
+               {\r
+                       return false;\r
+                       \r
+               }\r
+               \r
+               int size = argumentsList.size();\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       ValueNode v1 = (ValueNode)argumentsList.elementAt(index);\r
+                       ValueNode v2 = (ValueNode)other.argumentsList.elementAt(index);\r
+                       if (!v1.isEquivalent(v2)) \r
+                       {\r
+                               return false;\r
+                       }\r
+               }\r
+               return true;\r
+       }\r
+       public Visitable accept(Visitor v) throws StandardException \r
+       {\r
+               Visitable returnNode = v.visit(this);\r
+               \r
+               if (v.skipChildren(this) || v.stopTraversal())\r
+               {\r
+                       return returnNode;\r
+               }\r
+               \r
+               int size = argumentsList.size();\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       argumentsList.setElementAt(\r
+                                       (QueryTreeNode)(argumentsList.elementAt(index)).accept(v), index);\r
+               }\r
+               return returnNode;\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
+        * @return                                              The modified expression\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public ValueNode preprocess(int numTables,\r
+                                                               FromList outerFromList,\r
+                                                               SubqueryList outerSubqueryList,\r
+                                                               PredicateList outerPredicateList) \r
+                                       throws StandardException\r
+       {\r
+               int argumentsListSize = argumentsList.size();\r
+               for (int i=0; i < argumentsListSize; i++) {\r
+                       ((ValueNode)argumentsList.elementAt(i)).preprocess\r
+                               (numTables,\r
+                                outerFromList,\r
+                                outerSubqueryList,\r
+                                outerPredicateList);\r
+               }\r
+               return this;\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
+                       super.printSubNodes(depth);\r
+                       printLabel(depth, "argumentsList: [firstNonParameterNodeIdx=" +\r
+                                          firstNonParameterNodeIdx + "]" );\r
+                       int argumentsListSize = argumentsList.size();\r
+                       for (int i=0; i < argumentsListSize; i++) {\r
+                           ((ValueNode)argumentsList.elementAt(i)).treePrint(depth+1);\r
+                       }\r
+               }\r
+       }\r
+        \r
+}\r