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 / ValueNodeList.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/compile/ValueNodeList.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/compile/ValueNodeList.java
new file mode 100644 (file)
index 0000000..7c08021
--- /dev/null
@@ -0,0 +1,725 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.ValueNodeList\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.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.StringDataValue;\r
+import org.apache.derby.iapi.types.TypeId;\r
+\r
+import org.apache.derby.iapi.sql.compile.TypeCompiler;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.store.access.Qualifier;\r
+\r
+import org.apache.derby.iapi.util.JBitSet;\r
+\r
+import java.util.Vector;\r
+\r
+/**\r
+ * A ValueNodeList represents a list of ValueNodes within a specific predicate \r
+ * (eg, IN list, NOT IN list or BETWEEN) in a DML statement.  \r
+ * It extends QueryTreeNodeVector.\r
+ *\r
+ */\r
+\r
+public class ValueNodeList extends QueryTreeNodeVector\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
+                       for (int index = 0; index < size(); index++)\r
+                       {\r
+                               ValueNode               valueNode;\r
+                               valueNode = (ValueNode) elementAt(index);\r
+                               valueNode.treePrint(depth + 1);\r
+                       }\r
+               }\r
+       }\r
+\r
+\r
+       /**\r
+        * Add a ValueNode to the list.\r
+        *\r
+        * @param valueNode     A ValueNode to add to the list\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public void addValueNode(ValueNode valueNode) throws StandardException\r
+       {\r
+               addElement(valueNode);\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
+       public void     bindExpression(FromList fromList, \r
+                                                          SubqueryList subqueryList,\r
+                                                          Vector aggregateVector)\r
+                       throws StandardException\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       ValueNode vn = (ValueNode) elementAt(index);\r
+                       vn = vn.bindExpression(fromList, subqueryList,\r
+                                                                  aggregateVector);\r
+\r
+                       setElementAt(vn, index);\r
+               }\r
+       }\r
+\r
+\r
+       /**\r
+        * Generate a SQL->Java->SQL conversion tree any node in the list\r
+        * which is not a system built-in type.\r
+        * This is useful when doing comparisons, built-in functions, etc. on\r
+        * java types which have a direct mapping to system built-in types.\r
+        *\r
+        * @exception StandardException Thrown on error\r
+        */\r
+       public void genSQLJavaSQLTrees()\r
+               throws StandardException\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       ValueNode valueNode = (ValueNode) elementAt(index);\r
+                       \r
+                       if (valueNode.getTypeId().userType())\r
+                       {\r
+                               setElementAt(valueNode.genSQLJavaSQLTree(), index);\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Get the dominant DataTypeServices from the elements in the list. This\r
+        * method will also set the correct collation information on the dominant\r
+        * DataTypeService if we are dealing with character string datatypes.\r
+        *  \r
+        * Algorithm for determining collation information\r
+        * This method will check if it is dealing with character string datatypes.\r
+        * If yes, then it will check if all the character string datatypes have\r
+        * the same collation derivation and collation type associated with them.\r
+        * If not, then the resultant DTD from this method will have collation\r
+        * derivation of NONE. If yes, then the resultant DTD from this method will\r
+        * have the same collation derivation and collation type as all the \r
+        * character string datatypes.\r
+        * \r
+        * Note that this method calls DTD.getDominantType and that method returns\r
+        * the dominant type of the 2 DTDs involved in this method. That method \r
+        * sets the collation info on the dominant type following the algorithm\r
+        * mentioned in the comments of \r
+        * @see DataTypeDescriptor#getDominantType(DataTypeDescriptor, ClassFactory)\r
+        * With that algorithm, if one DTD has collation derivation of NONE and the\r
+        * other DTD has collation derivation of IMPLICIT, then the return DTD from\r
+        * DTD.getDominantType will have collation derivation of IMPLICIT. That is \r
+        * not the correct algorithm for aggregate operators. SQL standards says\r
+        * that if EVERY type has implicit derivation AND is of the same type, then \r
+        * the collation of the resultant will be of that type with derivation \r
+        * IMPLICIT. To provide this behavior for aggregate operator, we basically \r
+        * ignore the collation type and derivation picked by \r
+        * DataTypeDescriptor.getDominantType. Instead we let \r
+        * getDominantTypeServices use the simple algorithm listed at the top of\r
+        * this method's comments to determine the collation type and derivation \r
+        * for this ValueNodeList object.\r
+        * \r
+        * @return DataTypeServices             The dominant DataTypeServices.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public DataTypeDescriptor getDominantTypeServices() throws StandardException\r
+       {\r
+               DataTypeDescriptor      dominantDTS = null;\r
+               //Following 2 will hold the collation derivation and type of the first \r
+               //string operand. This collation information will be checked against\r
+               //the collation derivation and type of other string operands. If a \r
+               //mismatch is found, foundCollationMisMatch will be set to true.\r
+               int firstCollationDerivation = -1;\r
+               int firstCollationType = -1;\r
+               //As soon as we find 2 strings with different collations, we set the \r
+               //following flag to true. At the end of the method, if this flag is set \r
+               //to true then it means that we have operands with different collation\r
+               //types and hence the resultant dominant type will have to have the\r
+               //collation derivation of NONE. \r
+               boolean foundCollationMisMatch = false;\r
+\r
+               for (int index = 0; index < size(); index++)\r
+               {\r
+                       ValueNode                       valueNode;\r
+\r
+                       valueNode = (ValueNode) elementAt(index);\r
+                       if (valueNode.requiresTypeFromContext())\r
+                               continue;\r
+                       DataTypeDescriptor valueNodeDTS = valueNode.getTypeServices();\r
+\r
+                       if (valueNodeDTS.getTypeId().isStringTypeId())\r
+                       {\r
+                               if (firstCollationDerivation == -1)\r
+                               {\r
+                                       //found first string type. Initialize firstCollationDerivation\r
+                                       //and firstCollationType with collation information from \r
+                                       //that first string type operand.\r
+                                       firstCollationDerivation = valueNodeDTS.getCollationDerivation(); \r
+                                       firstCollationType = valueNodeDTS.getCollationType(); \r
+                               } else if (!foundCollationMisMatch)\r
+                               {\r
+                                       if (firstCollationDerivation != valueNodeDTS.getCollationDerivation())\r
+                                               foundCollationMisMatch = true;//collation derivations don't match\r
+                                       else if (firstCollationType != valueNodeDTS.getCollationType())\r
+                                               foundCollationMisMatch = true;//collation types don't match\r
+                               }\r
+                       }\r
+                       if (dominantDTS == null)\r
+                       {\r
+                               dominantDTS = valueNodeDTS;\r
+                       }\r
+                       else\r
+                       {\r
+                               dominantDTS = dominantDTS.getDominantType(valueNodeDTS, getClassFactory());\r
+                       }\r
+               }\r
+\r
+               //if following if returns true, then it means that we are dealing with \r
+               //string operands.\r
+               if (firstCollationDerivation != -1)\r
+               {\r
+                       if (foundCollationMisMatch) {\r
+                               //if we come here that it means that alll the string operands\r
+                               //do not have matching collation information on them. Hence the\r
+                               //resultant dominant DTD should have collation derivation of \r
+                               //NONE.\r
+                               dominantDTS.setCollationDerivation(StringDataValue.COLLATION_DERIVATION_NONE);\r
+                       }                       \r
+                       //if we didn't find any collation mismatch, then resultant dominant\r
+                       //DTD already has the correct collation information on it and hence\r
+                       //we don't need to do anything.\r
+               }\r
+\r
+               return dominantDTS;\r
+       }\r
+\r
+       /**\r
+        * Get the first non-null DataTypeServices from the elements in the list.\r
+        *\r
+        * @return DataTypeServices             The first non-null DataTypeServices.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public DataTypeDescriptor getTypeServices() throws StandardException\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       ValueNode valueNode = (ValueNode) elementAt(index);\r
+                       DataTypeDescriptor valueNodeDTS = valueNode.getTypeServices();\r
+\r
+                       if (valueNodeDTS != null)\r
+                       {\r
+                               return valueNodeDTS;\r
+                       }\r
+               }\r
+\r
+               return null;\r
+       }\r
+\r
+       /**\r
+        * Return whether or not all of the entries in the list have the same\r
+        * type precendence as the specified value.\r
+        *\r
+        * @param precedence    The specified precedence.\r
+        *\r
+        * @return      Whether or not all of the entries in the list have the same\r
+        *                      type precendence as the specified value.\r
+        */\r
+       boolean allSamePrecendence(int precedence)\r
+       throws StandardException\r
+       {\r
+               boolean allSame = true;\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       ValueNode                       valueNode;\r
+\r
+                       valueNode = (ValueNode) elementAt(index);\r
+                       DataTypeDescriptor valueNodeDTS = valueNode.getTypeServices();\r
+\r
+                       if (valueNodeDTS == null)\r
+                       {\r
+                               return false;\r
+                       }\r
+\r
+                       if (precedence != valueNodeDTS.getTypeId().typePrecedence())\r
+                       {\r
+                               return false;\r
+                       }\r
+               }\r
+\r
+               return allSame;\r
+       }\r
+\r
+\r
+       /**\r
+        * Make sure that passed ValueNode's type is compatible with the non-parameter elements in the ValueNodeList.\r
+        *\r
+        * @param leftOperand   Check for compatibility against this parameter's type\r
+        *\r
+        */\r
+       public void compatible(ValueNode leftOperand) throws StandardException\r
+       {\r
+               int                      size = size();\r
+               TypeId  leftType;\r
+               ValueNode               valueNode;\r
+               TypeCompiler leftTC;\r
+\r
+               leftType = leftOperand.getTypeId();\r
+               leftTC = leftOperand.getTypeCompiler();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       valueNode = (ValueNode) elementAt(index);\r
+                       if (valueNode.requiresTypeFromContext())\r
+                               continue;\r
+\r
+\r
+                       /*\r
+                       ** Are the types compatible to each other?  If not, throw an exception.\r
+                       */\r
+                       if (! leftTC.compatible(valueNode.getTypeId()))\r
+                       {\r
+                               throw StandardException.newException(SQLState.LANG_DB2_COALESCE_DATATYPE_MISMATCH,\r
+                                               leftType.getSQLTypeName(),\r
+                                               valueNode.getTypeId().getSQLTypeName()\r
+                                               );\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Determine whether or not the leftOperand is comparable() with all of\r
+        * the elements in the list. Throw an exception if any of them are not \r
+        * comparable.\r
+        *\r
+        * @param leftOperand   The left side of the expression\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void comparable(ValueNode leftOperand) throws StandardException\r
+       {\r
+               int                      size = size();\r
+               TypeId  leftType;\r
+               ValueNode               valueNode;\r
+\r
+               leftType = leftOperand.getTypeId();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       valueNode = (ValueNode) elementAt(index);\r
+\r
+                       /*\r
+                       ** Can the types be compared to each other?  If not, throw an\r
+                       ** exception.\r
+                       */\r
+                       if (! leftOperand.getTypeServices().comparable(valueNode.getTypeServices(),\r
+                                                                       false,\r
+                                                                       getClassFactory()))\r
+                       {\r
+                               throw StandardException.newException(SQLState.LANG_NOT_COMPARABLE, \r
+                                               leftOperand.getTypeServices().getSQLTypeNameWithCollation(),\r
+                                               valueNode.getTypeServices().getSQLTypeNameWithCollation()\r
+                                               );\r
+                       }\r
+               }\r
+       }\r
+\r
+       /** \r
+        * Determine whether or not any of the elements in the list are nullable.\r
+        *\r
+        * @return boolean      Whether or not any of the elements in the list \r
+        *                                      are nullable.\r
+        */\r
+       public boolean isNullable()\r
+       throws StandardException\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       if (((ValueNode) elementAt(index)).getTypeServices().isNullable())\r
+                       {\r
+                               return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+                                                                                \r
+       /**\r
+        * Does this list contain a ParameterNode?\r
+        *\r
+        * @return boolean      Whether or not the list contains a ParameterNode\r
+        */\r
+       public boolean containsParameterNode()\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       if (((ValueNode) elementAt(index)).requiresTypeFromContext())\r
+                       {\r
+                               return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+                                                                                \r
+       /**\r
+        * Does this list contain all ParameterNodes?\r
+        *\r
+        * @return boolean      Whether or not the list contains all ParameterNodes\r
+        */\r
+       public boolean containsAllParameterNodes()\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       if (! (((ValueNode) elementAt(index)).requiresTypeFromContext()))\r
+                       {\r
+                               return false;\r
+                       }\r
+               }\r
+               return true;\r
+       }\r
+\r
+       /**\r
+        * Does this list contain all ConstantNodes?\r
+        *\r
+        * @return boolean      Whether or not the list contains all ConstantNodes\r
+        */\r
+       public boolean containsAllConstantNodes()\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       if (! ((ValueNode) elementAt(index) instanceof ConstantNode))\r
+                       {\r
+                               return false;\r
+                       }\r
+               }\r
+               return true;\r
+       }\r
+\r
+       /**\r
+        * Does this list *only* contain constant and/or parameter nodes?\r
+        *\r
+        * @return boolean      True if every node in this list is either a constant\r
+        *  node or parameter node.\r
+        */\r
+       public boolean containsOnlyConstantAndParamNodes()\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       ValueNode vNode = (ValueNode)elementAt(index);\r
+                       if (!vNode.requiresTypeFromContext() &&\r
+                           !(vNode instanceof ConstantNode))\r
+                       {\r
+                               return false;\r
+                       }\r
+               }\r
+\r
+               return true;\r
+       }\r
+\r
+       /**\r
+        * Sort the entries in the list in ascending order.\r
+        * (All values are assumed to be constants.)\r
+        *\r
+        * @param judgeODV  In case of type not exactly matching, the judging type.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       void sortInAscendingOrder(DataValueDescriptor judgeODV)\r
+               throws StandardException\r
+       {\r
+               int size = size();\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(size > 0,\r
+                               "size() expected to be non-zero");\r
+               }\r
+\r
+               /* We use bubble sort to sort the list since we expect\r
+                * the list to be in sorted order > 90% of the time.\r
+                */\r
+               boolean continueSort = true;\r
+\r
+               while (continueSort)\r
+               {\r
+                       continueSort = false;\r
+                       \r
+                       for (int index = 1; index < size; index++)\r
+                       {\r
+                               ConstantNode currCN = (ConstantNode) elementAt(index);\r
+                               DataValueDescriptor currODV =\r
+                                        currCN.getValue();\r
+                               ConstantNode prevCN = (ConstantNode) elementAt(index - 1);\r
+                               DataValueDescriptor prevODV =\r
+                                        prevCN.getValue();\r
+\r
+                               /* Swap curr and prev if prev > curr */\r
+                               if ((judgeODV == null && (prevODV.compare(currODV)) > 0) ||\r
+                                       (judgeODV != null && judgeODV.greaterThan(prevODV, currODV).equals(true)))\r
+                               {\r
+                                       setElementAt(currCN, index - 1);\r
+                                       setElementAt(prevCN, index);\r
+                                       continueSort = true;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Set the descriptor for every ParameterNode in the list.\r
+        *\r
+        * @param descriptor    The DataTypeServices to set for the parameters\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void setParameterDescriptor(DataTypeDescriptor descriptor)\r
+                                               throws StandardException\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       ValueNode valueNode = (ValueNode) elementAt(index);\r
+                       if (valueNode.requiresTypeFromContext())\r
+                       {\r
+                               valueNode.setType(descriptor);\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Preprocess a ValueNodeList.  For now, we just preprocess each ValueNode\r
+        * in the list.\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 size = size();\r
+               ValueNode       valueNode;\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       valueNode = (ValueNode) elementAt(index);\r
+                       valueNode.preprocess(numTables,\r
+                                                                outerFromList, outerSubqueryList,\r
+                                                                outerPredicateList);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Remap all ColumnReferences in this tree to be clones of the\r
+        * underlying expression.\r
+        *\r
+        * @return ValueNodeList                        The remapped expression tree.\r
+        *\r
+        * @exception StandardException                 Thrown on error\r
+        */\r
+       public ValueNodeList remapColumnReferencesToExpressions()\r
+               throws StandardException\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       setElementAt(\r
+                               ((ValueNode) elementAt(index)).remapColumnReferencesToExpressions(),\r
+                               index);\r
+               }\r
+               return this;\r
+       }\r
+\r
+       /**\r
+        * Return whether or not this expression tree represents a constant expression.\r
+        *\r
+        * @return      Whether or not this expression tree represents a constant expression.\r
+        */\r
+       public boolean isConstantExpression()\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       boolean retcode;\r
+\r
+                       retcode = ((ValueNode) elementAt(index)).isConstantExpression();\r
+                       if (! retcode)\r
+                       {\r
+                               return retcode;\r
+                       }\r
+               }\r
+\r
+               return true;\r
+       }\r
+\r
+       /** @see ValueNode#constantExpression */\r
+       public boolean constantExpression(PredicateList whereClause)\r
+       {\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       boolean retcode;\r
+\r
+                       retcode =\r
+                               ((ValueNode) elementAt(index)).constantExpression(whereClause);\r
+                       if (! retcode)\r
+                       {\r
+                               return retcode;\r
+                       }\r
+               }\r
+\r
+               return true;\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 in lists when looking\r
+                * for null invariant predicates.\r
+                */\r
+               boolean pushable = true;\r
+               int size = size();\r
+\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       pushable = ((ValueNode) elementAt(index)).categorize(referencedTabs, simplePredsOnly) &&\r
+                                          pushable;\r
+               }\r
+\r
+               return pushable;\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
+        *                                                        (method calls and 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                        - constant\r
+        *\r
+        * @return      The variant type for the underlying expression.\r
+        * @exception StandardException thrown on error\r
+        */\r
+       protected int getOrderableVariantType() throws StandardException\r
+       {\r
+               int listType = Qualifier.CONSTANT;\r
+               int size = size();\r
+\r
+               /* If any element in the list is VARIANT then the \r
+                * entire expression is variant\r
+                * else it is SCAN_INVARIANT if any element is SCAN_INVARIANT\r
+                * else it is QUERY_INVARIANT.\r
+                */\r
+               for (int index = 0; index < size; index++)\r
+               {\r
+                       int curType = ((ValueNode) elementAt(index)).getOrderableVariantType();\r
+                       listType = Math.min(listType, curType);\r
+               }\r
+\r
+               return listType;\r
+       }\r
+}\r