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 / InListOperatorNode.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/compile/InListOperatorNode.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/compile/InListOperatorNode.java
new file mode 100644 (file)
index 0000000..71f2204
--- /dev/null
@@ -0,0 +1,776 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.InListOperatorNode\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.sql.compile.C_NodeTypes;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.reference.ClassName;\r
+\r
+import org.apache.derby.iapi.types.TypeId;\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+import org.apache.derby.iapi.services.compiler.LocalField;\r
+import org.apache.derby.iapi.services.loader.ClassFactory;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.sql.compile.Optimizable;\r
+\r
+import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;\r
+\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+\r
+import java.lang.reflect.Modifier;\r
+\r
+/**\r
+ * An InListOperatorNode represents an IN list.\r
+ *\r
+ */\r
+\r
+public final class InListOperatorNode extends BinaryListOperatorNode\r
+{\r
+       private boolean isOrdered;\r
+       private boolean sortDescending;\r
+\r
+       /**\r
+        * Initializer for a InListOperatorNode\r
+        *\r
+        * @param leftOperand           The left operand of the node\r
+        * @param rightOperandList      The right operand list of the node\r
+        */\r
+\r
+       public void init(Object leftOperand, Object rightOperandList)\r
+       {\r
+               init(leftOperand, rightOperandList, "IN", "in");\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 "isOrdered: " + isOrdered + "\n" +\r
+                               super.toString();\r
+               }\r
+               else\r
+               {\r
+                       return "";\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Create a shallow copy of this InListOperatorNode whose operands are\r
+        * the same as this node's operands.  Copy over all other necessary\r
+        * state, as well.\r
+        */\r
+       protected InListOperatorNode shallowCopy() throws StandardException\r
+       {\r
+               InListOperatorNode ilon =\r
+                        (InListOperatorNode)getNodeFactory().getNode(\r
+                               C_NodeTypes.IN_LIST_OPERATOR_NODE,\r
+                               leftOperand,\r
+                               rightOperandList,\r
+                               getContextManager());\r
+\r
+               ilon.copyFields(this);\r
+               if (isOrdered)\r
+                       ilon.markAsOrdered();\r
+\r
+               if (sortDescending)\r
+                       ilon.markSortDescending();\r
+\r
+               return ilon;\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
+        * @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
+               super.preprocess(numTables,\r
+                                                outerFromList, outerSubqueryList,\r
+                                                outerPredicateList);\r
+\r
+               /* Check for the degenerate case of a single element in the IN list.\r
+                * If found, then convert to "=".\r
+                */\r
+               if (rightOperandList.size() == 1)\r
+               {\r
+                       BinaryComparisonOperatorNode equal = \r
+                               (BinaryComparisonOperatorNode) getNodeFactory().getNode(\r
+                                               C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE,\r
+                                               leftOperand, \r
+                                               (ValueNode) rightOperandList.elementAt(0),\r
+                                               getContextManager());\r
+                       /* Set type info for the operator node */\r
+                       equal.bindComparisonOperator();\r
+                       return equal;\r
+               }\r
+               else if ((leftOperand instanceof ColumnReference) &&\r
+                                rightOperandList.containsOnlyConstantAndParamNodes())\r
+               {\r
+                       /* At this point we have an IN-list made up of constant and/or\r
+                        * parameter values.  Ex.:\r
+                        *\r
+                        *  select id, name from emp where id in (34, 28, ?)\r
+                        *\r
+                        * Since the optimizer does not recognize InListOperatorNodes\r
+                        * as potential start/stop keys for indexes, it (the optimizer)\r
+                        * may estimate that the cost of using any of the indexes would\r
+                        * be too high.  So we could--and probably would--end up doing\r
+                        * a table scan on the underlying base table. But if the number\r
+                        * of rows in the base table is significantly greater than the\r
+                        * number of values in the IN-list, scanning the base table can\r
+                        * be overkill and can lead to poor performance.  And further,\r
+                        * choosing to use an index but then scanning the entire index\r
+                        * can be slow, too. DERBY-47.\r
+                        *\r
+                        * What we do, then, is create an "IN-list probe predicate",\r
+                        * which is an internally generated equality predicate with a\r
+                        * parameter value on the right.  So for the query shown above\r
+                        * the probe predicate would be "id = ?".  We then replace\r
+                        * this InListOperatorNode with the probe predicate during\r
+                        * optimization.  The optimizer in turn recognizes the probe\r
+                        * predicate, which is disguised to look like a typical binary\r
+                        * equality, as a potential start/stop key for any indexes.\r
+                        * This start/stop key potential then factors into the estimated\r
+                        * cost of probing the indexes, which leads to a more reasonable\r
+                        * estimate and thus makes it more likely that the optimizer\r
+                        * will choose to use an index vs a table scan.  That done, we\r
+                        * then use the probe predicate to perform multiple execution-\r
+                        * time "probes" on the index--instead of doing a range index\r
+                        * scan--which eliminates unnecessary scanning. For more see\r
+                        * execute/MultiProbeTableScanResultSet.java.\r
+                        *\r
+                        * With this approach we know that regardless of how large the\r
+                        * base table is, we'll only have to probe the index a max of\r
+                        * N times, where "N" is the size of the IN-list. If N is\r
+                        * significantly less than the number of rows in the table, or\r
+                        * is significantly less than the number of rows between the\r
+                        * min value and the max value in the IN-list, this selective\r
+                        * probing can save us a lot of time.\r
+                        *\r
+                        * Note: We will do fewer than N probes if there are duplicates\r
+                        * in the list.\r
+                        *\r
+                        * Note also that, depending on the relative size of the IN-list\r
+                        * verses the number of rows in the table, it may actually be\r
+                        * better to just do a table scan--especially if there are fewer\r
+                        * rows in the table than there are in the IN-list.  So even though\r
+                        * we create a "probe predicate" and pass it to the optimizer, it\r
+                        * (the optimizer) may still choose to do a table scan.  If that\r
+                        * happens then we'll "revert" the probe predicate back to its\r
+                        * original form (i.e. to this InListOperatorNode) during code\r
+                        * generation, and then we'll use it as a regular IN-list\r
+                        * restriction when it comes time to execute.\r
+                        */\r
+\r
+                       boolean allConstants = rightOperandList.containsAllConstantNodes();\r
+\r
+                       /* If we have all constants then sort them now.  This allows us to\r
+                        * skip the sort at execution time (we have to sort them so that\r
+                        * we can eliminate duplicate IN-list values).  If we have one\r
+                        * or more parameter nodes then we do *not* sort the values here\r
+                        * because we do not (and cannot) know what values the parameter(s)\r
+                        * will have.  In that case we'll sort the values at execution\r
+                        * time. \r
+                        */\r
+                       if (allConstants)\r
+                       {\r
+                               /* When sorting or choosing min/max in the list, if types\r
+                                * are not an exact match then we have to use the *dominant*\r
+                                * type across all values, where "all values" includes the\r
+                                * left operand.  Otherwise we can end up with incorrect\r
+                                * results.\r
+                                *\r
+                                * Note that it is *not* enough to just use the left operand's\r
+                                * type as the judge because we have no guarantee that the\r
+                                * left operand has the dominant type.  If, for example, the\r
+                                * left operand has type INTEGER and all (or any) values in\r
+                                * the IN list have type DECIMAL, use of the left op's type\r
+                                * would lead to comparisons with truncated values and could\r
+                                * therefore lead to an incorrect sort order. DERBY-2256.\r
+                                */\r
+                               DataTypeDescriptor targetType = leftOperand.getTypeServices();\r
+                               TypeId judgeTypeId = targetType.getTypeId();\r
+\r
+                               if (!rightOperandList.allSamePrecendence(\r
+                                       judgeTypeId.typePrecedence()))\r
+                               {\r
+                                       /* Iterate through the entire list of values to find out\r
+                                        * what the dominant type is.\r
+                                        */\r
+                                       ClassFactory cf = getClassFactory();\r
+                                       int sz = rightOperandList.size();\r
+                                       for (int i = 0; i < sz; i++)\r
+                                       {\r
+                                               ValueNode vn = (ValueNode)rightOperandList.elementAt(i);\r
+                                               targetType =\r
+                                                       targetType.getDominantType(\r
+                                                               vn.getTypeServices(), cf);\r
+                                       }\r
+                               }\r
\r
+                               /* Now wort the list in ascending order using the dominant\r
+                                * type found above.\r
+                                */\r
+                               DataValueDescriptor judgeODV = targetType.getNull();\r
+\r
+                               rightOperandList.sortInAscendingOrder(judgeODV);\r
+                               isOrdered = true;\r
+\r
+                               ValueNode minValue = (ValueNode)rightOperandList.elementAt(0);\r
+                               ValueNode maxValue =\r
+                                       (ValueNode)rightOperandList.elementAt(\r
+                                               rightOperandList.size() - 1);\r
+\r
+                               /* Handle the degenerate case where the min and the max\r
+                                * are the same value.  Note (again) that we need to do\r
+                                * this comparison using the dominant type found above.\r
+                                */\r
+                               DataValueDescriptor minODV =\r
+                                       ((ConstantNode) minValue).getValue();\r
+                               DataValueDescriptor maxODV =\r
+                                        ((ConstantNode) maxValue).getValue();\r
+\r
+                               if (judgeODV.equals(minODV, maxODV).equals(true))\r
+                               {\r
+                                       BinaryComparisonOperatorNode equal = \r
+                                               (BinaryComparisonOperatorNode)getNodeFactory().getNode(\r
+                                                       C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE,\r
+                                                       leftOperand, \r
+                                                       minValue,\r
+                                                       getContextManager());\r
+                                       /* Set type info for the operator node */\r
+                                       equal.bindComparisonOperator();\r
+                                       return equal;\r
+                               }\r
+                       }\r
+\r
+                       /* Create a parameter node to serve as the right operand of\r
+                        * the probe predicate.  We intentionally use a parameter node\r
+                        * instead of a constant node because the IN-list has more than\r
+                        * one value (some of which may be unknown at compile time, i.e.\r
+                        * if they are parameters), so we don't want an estimate based\r
+                        * on any single literal.  Instead we want a generic estimate\r
+                        * of the cost to retrieve the rows matching some _unspecified_\r
+                        * value (namely, one of the values in the IN-list, but we\r
+                        * don't know which one).  That's exactly what a parameter\r
+                        * node gives us.\r
+                        *\r
+                        * Note: If the IN-list only had a single value then we would\r
+                        * have taken the "if (rightOperandList.size() == 1)" branch\r
+                        * above and thus would not be here.\r
+                        *\r
+                        * We create the parameter node based on the first value in\r
+                        * the list.  This is arbitrary and should not matter in the\r
+                        * big picture.\r
+                        */\r
+                       ValueNode srcVal = (ValueNode) rightOperandList.elementAt(0);\r
+                       ParameterNode pNode =\r
+                               (ParameterNode) getNodeFactory().getNode(\r
+                                       C_NodeTypes.PARAMETER_NODE,\r
+                                       new Integer(0),\r
+                                       null, // default value\r
+                                       getContextManager());\r
+\r
+                       DataTypeDescriptor pType = srcVal.getTypeServices();\r
+                       pNode.setType(pType);\r
+\r
+                       /* If we choose to use the new predicate for execution-time\r
+                        * probing then the right operand will function as a start-key\r
+                        * "place-holder" into which we'll store the different IN-list\r
+                        * values as we iterate through them.  This means we have to\r
+                        * generate a valid value for the parameter node--i.e. for the\r
+                        * right side of the probe predicate--in order to have a valid\r
+                        * execution-time placeholder.  To do that we pass the source\r
+                        * value from which we found the type down to the new, "fake"\r
+                        * parameter node.  Then, when it comes time to generate the\r
+                        * parameter node, we'll just generate the source value as our\r
+                        * place-holder.  See ParameterNode.generateExpression().\r
+                        *\r
+                        * Note: the actual value of the "place-holder" does not matter\r
+                        * because it will be clobbered by the various IN-list values\r
+                        * (which includes "srcVal" itself) as we iterate through them\r
+                        * during execution.\r
+                        */\r
+                       pNode.setValueToGenerate(srcVal);\r
+\r
+                       /* Finally, create the "column = ?" equality that serves as the\r
+                        * basis for the probe predicate.  We store a reference to "this"\r
+                        * node inside the probe predicate so that, if we later decide\r
+                        * *not* to use the probe predicate for execution time index\r
+                        * probing, we can revert it back to its original form (i.e.\r
+                        * to "this").\r
+                        */\r
+                       BinaryComparisonOperatorNode equal = \r
+                               (BinaryComparisonOperatorNode) getNodeFactory().getNode(\r
+                                       C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE,\r
+                                       leftOperand, \r
+                                       pNode,\r
+                                       this,\r
+                                       getContextManager());\r
+\r
+                       /* Set type info for the operator node */\r
+                       equal.bindComparisonOperator();\r
+                       return equal;\r
+               }\r
+               else\r
+               {\r
+                       return this;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Eliminate NotNodes in the current query block.  We traverse the tree, \r
+        * inverting ANDs and ORs and eliminating NOTs as we go.  We stop at \r
+        * ComparisonOperators and boolean expressions.  We invert \r
+        * ComparisonOperators and replace boolean expressions with \r
+        * boolean expression = false.\r
+        * NOTE: Since we do not recurse under ComparisonOperators, there\r
+        * still could be NotNodes left in the tree.\r
+        *\r
+        * @param       underNotNode            Whether or not we are under a NotNode.\r
+        *                                                      \r
+        *\r
+        * @return              The modified expression\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       ValueNode eliminateNots(boolean underNotNode) \r
+                                       throws StandardException\r
+       {\r
+               AndNode                                          newAnd = null;\r
+               BinaryComparisonOperatorNode leftBCO;\r
+               BinaryComparisonOperatorNode rightBCO;\r
+               int                                                      listSize = rightOperandList.size();\r
+               ValueNode                                        leftSide;\r
+\r
+               if (SanityManager.DEBUG)\r
+               SanityManager.ASSERT(listSize > 0,\r
+                       "rightOperandList.size() is expected to be > 0");\r
+\r
+               if (! underNotNode)\r
+               {\r
+                       return this;\r
+               }\r
+\r
+               /* we want to convert the IN List into = OR = ... as\r
+                * described below.  \r
+                */\r
+\r
+               /* Convert:\r
+                *              leftO IN rightOList.elementAt(0) , rightOList.elementAt(1) ...\r
+                * to:\r
+                *              leftO <> rightOList.elementAt(0) AND leftO <> rightOList.elementAt(1) ...\r
+                * NOTE - We do the conversion here since the single table clauses\r
+                * can be pushed down and the optimizer may eventually have a filter factor\r
+                * for <>.\r
+                */\r
+\r
+               /* leftO <> rightOList.at(0) */\r
+               /* If leftOperand is a ColumnReference, it may be remapped during optimization, and that\r
+                * requires each <> node to have a separate object.\r
+                */\r
+               ValueNode leftClone = (leftOperand instanceof ColumnReference) ? leftOperand.getClone() : leftOperand;\r
+               leftBCO = (BinaryComparisonOperatorNode) \r
+                                       getNodeFactory().getNode(\r
+                                               C_NodeTypes.BINARY_NOT_EQUALS_OPERATOR_NODE,\r
+                                               leftClone,\r
+                                               (ValueNode) rightOperandList.elementAt(0),\r
+                                               getContextManager());\r
+               /* Set type info for the operator node */\r
+               leftBCO.bindComparisonOperator();\r
+\r
+               leftSide = leftBCO;\r
+\r
+               for (int elemsDone = 1; elemsDone < listSize; elemsDone++)\r
+               {\r
+\r
+                       /* leftO <> rightOList.elementAt(elemsDone) */\r
+                       leftClone = (leftOperand instanceof ColumnReference) ? leftOperand.getClone() : leftOperand;\r
+                       rightBCO = (BinaryComparisonOperatorNode) \r
+                                               getNodeFactory().getNode(\r
+                                                       C_NodeTypes.BINARY_NOT_EQUALS_OPERATOR_NODE,\r
+                                                       leftClone,\r
+                                                       (ValueNode) rightOperandList.elementAt(elemsDone),\r
+                                                       getContextManager());\r
+                       /* Set type info for the operator node */\r
+                       rightBCO.bindComparisonOperator();\r
+\r
+                       /* Create the AND */\r
+                       newAnd = (AndNode) getNodeFactory().getNode(\r
+                                                                                               C_NodeTypes.AND_NODE,\r
+                                                                                               leftSide,\r
+                                                                                               rightBCO,\r
+                                                                                               getContextManager());\r
+                       newAnd.postBindFixup();\r
+\r
+                       leftSide = newAnd;\r
+               }\r
+\r
+               return leftSide;\r
+       }\r
+\r
+       /**\r
+        * See if this IN list operator is referencing the same table.\r
+        *\r
+        * @param cr    The column reference.\r
+        *\r
+        * @return      true if in list references the same table as in cr.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public boolean selfReference(ColumnReference cr)\r
+               throws StandardException\r
+       {\r
+               int size = rightOperandList.size();\r
+               for (int i = 0; i < size; i++)\r
+               {\r
+                       ValueNode vn = (ValueNode) rightOperandList.elementAt(i);\r
+                       if (vn.getTablesReferenced().get(cr.getTableNumber()))\r
+                               return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       /**\r
+        * The selectivity for an "IN" predicate is generally very small.\r
+        * This is an estimate applicable when in list are not all constants.\r
+        */\r
+       public double selectivity(Optimizable optTable)\r
+       {\r
+               return 0.3d;\r
+       }\r
\r
+       /**\r
+        * Do code generation for this IN list operator.\r
+        *\r
+        * @param acb   The ExpressionClassBuilder for the class we're generating\r
+        * @param mb The MethodBuilder 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                     listSize = rightOperandList.size();\r
+               String          resultTypeName;\r
+               String          receiverType = ClassName.DataValueDescriptor;\r
+       \r
+               String          leftInterfaceType = ClassName.DataValueDescriptor;\r
+               String          rightInterfaceType = ClassName.DataValueDescriptor + "[]";\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(listSize > 0,\r
+                               "listSize is expected to be > 0");\r
+               }\r
+\r
+               /*\r
+               ** There are 2 parts to the code generation for an IN list -\r
+               ** the code in the constructor and the code for the expression evaluation.\r
+               ** The code that gets generated for the constructor is:\r
+               **              DataValueDescriptor[] field = new DataValueDescriptor[size];\r
+               **      For each element in the IN list that is a constant, we also generate:\r
+               **              field[i] = rightOperandList[i];\r
+               **      \r
+               ** If the IN list is composed entirely of constants, then we generate the\r
+               ** the following:\r
+               **              leftOperand.in(rightOperandList, leftOperand, isNullable(), ordered, result);\r
+               **\r
+               ** Otherwise, we create a new method.  This method contains the \r
+               ** assignment of the non-constant elements into the array and the call to the in()\r
+               ** method, which is in the new method's return statement.  We then return a call\r
+               ** to the new method.\r
+               */\r
+\r
+               receiver = leftOperand;\r
+\r
+               /* Figure out the result type name */\r
+               resultTypeName = getTypeCompiler().interfaceName();\r
+\r
+               // Generate the code to build the array\r
+               LocalField arrayField = generateListAsArray(acb, mb);\r
+\r
+               /*\r
+               ** Call the method for this operator.\r
+               */\r
+               /*\r
+               ** Generate (field = <left expression>).  This assignment is\r
+               ** used as the receiver of the method call for this operator,\r
+               ** and the field is used as the left operand:\r
+               **\r
+               **      (field = <left expression>).method(field, <right expression>...)\r
+               */\r
+\r
+               //LocalField receiverField =\r
+               //      acb.newFieldDeclaration(Modifier.PRIVATE, receiverType);\r
+\r
+               leftOperand.generateExpression(acb, mb);\r
+               mb.dup();\r
+               //mb.putField(receiverField); // instance for method call\r
+               /*mb.getField(receiverField);*/ mb.upCast(leftInterfaceType); // first arg\r
+               mb.getField(arrayField); // second arg\r
+               mb.push(isOrdered); // third arg\r
+               mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, 3);\r
+       }\r
+\r
+       /**\r
+        * Generate the code to create an array of DataValueDescriptors that\r
+        * will hold the IN-list values at execution time.  The array gets\r
+        * created in the constructor.  All constant elements in the array\r
+        * are initialized in the constructor.  All non-constant elements,\r
+        * if any, are initialized each time the IN list is evaluated.\r
+        *\r
+        * @param acb The ExpressionClassBuilder for the class we're generating\r
+        * @param mb The MethodBuilder the expression will go into\r
+        */\r
+       protected LocalField generateListAsArray(ExpressionClassBuilder acb,\r
+               MethodBuilder mb) throws StandardException\r
+       {\r
+               int listSize = rightOperandList.size();\r
+               LocalField arrayField = acb.newFieldDeclaration(\r
+                       Modifier.PRIVATE, ClassName.DataValueDescriptor + "[]");\r
+\r
+               /* Assign the initializer to the DataValueDescriptor[] field */\r
+               MethodBuilder cb = acb.getConstructor();\r
+               cb.pushNewArray(ClassName.DataValueDescriptor, listSize);\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 < listSize; index++)\r
+               {\r
+                       MethodBuilder setArrayMethod;\r
+       \r
+                       if (rightOperandList.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); // first arg\r
+                       ((ValueNode) rightOperandList.elementAt(index)).generateExpression(acb, setArrayMethod);\r
+                       setArrayMethod.upCast(ClassName.DataValueDescriptor); // second arg\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
+               return arrayField;\r
+       }\r
+\r
+\r
+       /**\r
+        * Generate start/stop key for this IN list operator.  Bug 3858.\r
+        *\r
+        * @param isAsc         is the index ascending on the column in question\r
+        * @param isStartKey    are we generating start key or not\r
+        * @param acb   The ExpressionClassBuilder for the class we're generating\r
+        * @param mb The MethodBuilder the expression will go into\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void generateStartStopKey(boolean isAsc, boolean isStartKey,\r
+                                                                        ExpressionClassBuilder acb,\r
+                                                                        MethodBuilder mb)\r
+                                                                                          throws StandardException\r
+       {\r
+               /* left side of the "in" operator is our "judge" when we try to get\r
+                * the min/max value of the operands on the right side.  Judge's type\r
+                * is important for us, and is input parameter to min/maxValue.\r
+                */\r
+               int leftTypeFormatId = leftOperand.getTypeId().getTypeFormatId();\r
+               int leftJDBCTypeId = leftOperand.getTypeId().isUserDefinedTypeId() ?\r
+                                                               leftOperand.getTypeId().getJDBCTypeId() : -1;\r
+\r
+               int listSize = rightOperandList.size();\r
+               int numLoops, numValInLastLoop, currentOpnd = 0;\r
+\r
+               /* We first calculate how many times (loops) we generate a call to\r
+                * min/maxValue function accumulatively, since each time it at most\r
+                * takes 4 input values.  An example of the calls generated will be:\r
+                * minVal(minVal(...minVal(minVal(v1,v2,v3,v4,judge), v5,v6,v7,judge),\r
+                *        ...), vn-1, vn, NULL, judge)\r
+                * Unused value parameters in the last call are filled with NULLs.\r
+                */\r
+               if (listSize < 5)\r
+               {\r
+                       numLoops = 1;\r
+                       numValInLastLoop = (listSize - 1) % 4 + 1;\r
+               }\r
+               else\r
+               {\r
+                       numLoops = (listSize - 5) / 3 + 2;\r
+                       numValInLastLoop = (listSize - 5) % 3 + 1;\r
+               }\r
+\r
+               for (int i = 0; i < numLoops; i++)\r
+               {\r
+                       /* generate value parameters of min/maxValue\r
+                        */\r
+                       int numVals = (i == numLoops - 1) ? numValInLastLoop :\r
+                                                         ((i == 0) ? 4 : 3);\r
+                       for (int j = 0; j < numVals; j++)\r
+                       {\r
+                               ValueNode vn = (ValueNode) rightOperandList.elementAt(currentOpnd++);\r
+                               vn.generateExpression(acb, mb);\r
+                               mb.upCast(ClassName.DataValueDescriptor);\r
+                       }\r
+\r
+                       /* since we have fixed number of input values (4), unused ones\r
+                        * in the last loop are filled with NULLs\r
+                        */\r
+                       int numNulls = (i < numLoops - 1) ? 0 :\r
+                                                       ((i == 0) ? 4 - numValInLastLoop : 3 - numValInLastLoop);\r
+                       for (int j = 0; j < numNulls; j++)\r
+                               mb.pushNull(ClassName.DataValueDescriptor);\r
+\r
+                       /* have to put judge's types in the end\r
+                        */\r
+                       mb.push(leftTypeFormatId);\r
+                       mb.push(leftJDBCTypeId);\r
+\r
+                       /* decide to get min or max value\r
+                        */\r
+                       String methodName;\r
+                       if ((isAsc && isStartKey) || (! isAsc && ! isStartKey))\r
+                               methodName = "minValue";\r
+                       else\r
+                               methodName = "maxValue";\r
+               \r
+                       mb.callMethod(VMOpcode.INVOKESTATIC, ClassName.BaseExpressionActivation, methodName, ClassName.DataValueDescriptor, 6);\r
+\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Indicate that the IN-list values for this node are ordered (i.e. they\r
+        * are all constants and they have been sorted).\r
+        */\r
+       protected void markAsOrdered()\r
+       {\r
+               isOrdered = true;\r
+       }\r
+\r
+       /**\r
+        * Indicate that the IN-list values for this node must be sorted\r
+        * in DESCENDING order.  This only applies to in-list "multi-probing",\r
+        * where the rows are processed in the order of the IN list elements\r
+        * themselves.  In that case, any requirement to sort the rows in\r
+        * descending order means that the values in the IN list have to\r
+        * be sorted in descending order, as well.\r
+        */\r
+       protected void markSortDescending()\r
+       {\r
+               sortDescending = true;\r
+       }\r
+\r
+       /**\r
+        * Return whether or not the IN-list values for this node are ordered.\r
+        * This is used for determining whether or not we need to do an execution-\r
+        * time sort.\r
+        */\r
+       protected boolean isOrdered()\r
+       {\r
+               return isOrdered;\r
+       } \r
+\r
+       /**\r
+        * Return whether or not the IN-list values for this node must be\r
+        * sorted in DESCENDING order.\r
+        */\r
+       protected boolean sortDescending()\r
+       {\r
+               return sortDescending;\r
+       } \r
+}\r