Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / compile / Predicate.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/Predicate.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/Predicate.java
new file mode 100644 (file)
index 0000000..3336d58
--- /dev/null
@@ -0,0 +1,1399 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.Predicate\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.impl.sql.compile.ExpressionClassBuilder;\r
+import org.apache.derby.impl.sql.compile.ActivationClassBuilder;\r
+\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+import org.apache.derby.iapi.sql.compile.Visitable;\r
+import org.apache.derby.iapi.sql.compile.Visitor;\r
+import org.apache.derby.iapi.sql.compile.OptimizablePredicate;\r
+import org.apache.derby.iapi.sql.compile.Optimizable;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+\r
+import org.apache.derby.iapi.store.access.ScanController;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+import org.apache.derby.iapi.util.JBitSet;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Hashtable;\r
+\r
+/**\r
+ * A Predicate represents a top level predicate.\r
+ *\r
+ */\r
+\r
+public final class Predicate extends QueryTreeNode implements OptimizablePredicate,\r
+                                                                                                               Comparable\r
+{\r
+       /* Top of the predicate */\r
+       AndNode         andNode;\r
+       boolean         pushable;\r
+       /* Bit map of referenced tables */\r
+       JBitSet         referencedSet;\r
+       /* Join clauses are placed into equivalence classes when applying transitive\r
+        * closure for join clauses.  This is useful for eliminating redundant predicates.\r
+        */\r
+       int                     equivalenceClass = -1;\r
+       int                     indexPosition;\r
+       protected boolean startKey;\r
+       protected boolean stopKey;\r
+       protected boolean isQualifier;\r
+\r
+       /* Hashtable used for tracking the search clause types that have been\r
+        * pushed through this predicate (if an equijoin) via transitive closure.\r
+        */\r
+       private Hashtable searchClauseHT;\r
+\r
+       // Whether or not this predicate has been scoped; see the\r
+       // getPredScopedForResultSet() method of this class for more.\r
+       private boolean scoped;\r
+\r
+       /**\r
+        * Initializer.\r
+        *\r
+        * @param andNode               The top of the predicate         \r
+        * @param referencedSet Bit map of referenced tables\r
+        */\r
+\r
+       public void init(Object andNode, Object referencedSet)\r
+       {\r
+               this.andNode = (AndNode) andNode;\r
+               pushable = false;\r
+               this.referencedSet = (JBitSet) referencedSet;\r
+               scoped = false;\r
+       }\r
+\r
+       /*\r
+        *  Optimizable interface\r
+        */\r
+\r
+       /**\r
+        * @see org.apache.derby.iapi.sql.compile.OptimizablePredicate#getReferencedMap\r
+        */\r
+       public JBitSet getReferencedMap()\r
+       {\r
+               return referencedSet;\r
+       }\r
+\r
+       /**\r
+        * @see org.apache.derby.iapi.sql.compile.OptimizablePredicate#hasSubquery\r
+        */\r
+       public boolean hasSubquery()\r
+       {\r
+               /* RESOLVE - Currently, we record whether or not a predicate is pushable based\r
+                * on whether or not it contains a subquery or method call, but we do not\r
+                * record the underlying info.\r
+                */\r
+               return ! pushable;\r
+       }\r
+\r
+       /**\r
+        * @see org.apache.derby.iapi.sql.compile.OptimizablePredicate#hasMethodCall\r
+        */\r
+       public boolean hasMethodCall()\r
+       {\r
+               /* RESOLVE - Currently, we record whether or not a predicate is pushable based\r
+                * on whether or not it contains a subquery or method call, but we do not\r
+                * record the underlying info.\r
+                */\r
+               return ! pushable;\r
+       }\r
+\r
+       /** @see OptimizablePredicate#markStartKey */\r
+       public void markStartKey()\r
+       {\r
+               startKey = true;\r
+       }\r
+\r
+       /** @see OptimizablePredicate#isStartKey */\r
+       public boolean isStartKey()\r
+       {\r
+               return startKey;\r
+       }\r
+\r
+       /** @see OptimizablePredicate#markStopKey */\r
+       public void markStopKey()\r
+       {\r
+               stopKey = true;\r
+       }\r
+\r
+       /** @see OptimizablePredicate#isStopKey */\r
+       public boolean isStopKey()\r
+       {\r
+               return stopKey;\r
+       }\r
+\r
+       /** @see OptimizablePredicate#markQualifier */\r
+       public void markQualifier()\r
+       {\r
+               isQualifier = true;\r
+       }\r
+\r
+       /** @see OptimizablePredicate#isQualifier */\r
+       public boolean isQualifier()\r
+       {\r
+               return isQualifier;\r
+       }\r
+\r
+       /** @see OptimizablePredicate#compareWithKnownConstant */\r
+       public boolean compareWithKnownConstant(Optimizable optTable, boolean considerParameters)\r
+       {\r
+               boolean retval = false;\r
+               RelationalOperator relop = getRelop();\r
+\r
+               /* if this is for "in" operator node's dynamic start/stop key, relop is\r
+                * null, and it's not comparing with constant, beetle 3858\r
+                */\r
+               if (!isRelationalOpPredicate())\r
+                       return false;\r
+\r
+               if (relop.compareWithKnownConstant(optTable, considerParameters))\r
+                       retval = true;\r
+\r
+               return retval;\r
+       }\r
+\r
+       public int hasEqualOnColumnList(int[] baseColumnPositions,\r
+                                                                               Optimizable optTable)\r
+               throws StandardException\r
+       {\r
+               RelationalOperator relop = getRelop();\r
+\r
+               if (!isRelationalOpPredicate())\r
+                       return -1;\r
+               \r
+               if (!(relop.getOperator() == RelationalOperator.EQUALS_RELOP))\r
+                       return -1;\r
+                       \r
+               for (int i = 0; i < baseColumnPositions.length; i++)\r
+               {\r
+                       ColumnReference cr = relop.getColumnOperand(optTable, \r
+                                                                                                               baseColumnPositions[i]);\r
+               \r
+                       if (cr == null)\r
+                               continue;\r
+                       \r
+                       if (relop.selfComparison(cr))\r
+                               continue;\r
+\r
+                       // If I made it thus far in the loop, we've found\r
+                       // something.\r
+                       return i;\r
+               }\r
+               \r
+               return -1;\r
+       }\r
+\r
+       /**\r
+        * @see OptimizablePredicate#getCompareValue\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public DataValueDescriptor getCompareValue(Optimizable optTable)\r
+               throws StandardException\r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(compareWithKnownConstant(optTable, true),\r
+                               "Cannot get the compare value if not comparing with a known constant.");\r
+               }\r
+\r
+               RelationalOperator relop = getRelop();\r
+\r
+               return relop.getCompareValue(optTable);\r
+       }\r
+\r
+       /** @see OptimizablePredicate#equalsComparisonWithConstantExpression */\r
+       public boolean equalsComparisonWithConstantExpression(Optimizable optTable)\r
+       {\r
+               boolean retval = false;\r
+\r
+               if (isRelationalOpPredicate())\r
+               {\r
+                       retval = getRelop().equalsComparisonWithConstantExpression(optTable);\r
+               }\r
+\r
+               return retval;\r
+       }\r
+\r
+       /** @see OptimizablePredicate#selectivity */\r
+       public double selectivity(Optimizable optTable)\r
+       throws StandardException\r
+       {\r
+               return andNode.getLeftOperand().selectivity(optTable);\r
+       }\r
+\r
+       /** @see OptimizablePredicate#getIndexPosition */\r
+       public int getIndexPosition()\r
+       {\r
+               return indexPosition;\r
+       }\r
+\r
+\r
+       /* Comparable interface */\r
+\r
+       public int compareTo(Object other)\r
+       {\r
+               Predicate       otherPred = (Predicate) other;\r
+\r
+               /* Not all operators are "equal". If the predicates are on the\r
+                * same key column, then a "=" opertor takes precedence over all\r
+                * other operators.  This ensures that the "=" will be both the start\r
+                * and stop predicates.  Otherwise, we could end up with it being one\r
+                * but not the other and get incorrect results.\r
+                *\r
+                * Also, we want "<>" to come after all the other operators.\r
+                * Other parts of the optimizer use the first predicate on an index\r
+                * column to determine the cost of using the index, so we want the\r
+                * "<>" to come last because it's not useful for limiting the scan.\r
+                *\r
+                * In other words, P1 is before() P2 if:\r
+                *              o  The P1.indexPosition < P2.indexPosition\r
+                *      or  o  P1.indexPosition == P2.indexPosition and\r
+                *                 P1's operator is ("=" or IS NULL) and\r
+                *                 P2's operator is not ("=" or IS NULL)\r
+                * or   o  P1.indexPosition == P2.indexPosition and\r
+                *                 P1's operator is not ("<>" or IS NOT NULL) and\r
+                *                 P2's operator is ("<>" or IS NOT NULL)\r
+                *\r
+                * (We have to impose an arbitrary, but reproducible ordering\r
+                * on the the "=" predicates on the same column, otherwise an\r
+                * ASSERTion, that after the predicates are order, Pn+1 is not\r
+                * before() Pn, will be violated.\r
+                */\r
+\r
+               int otherIndexPosition = otherPred.getIndexPosition();\r
+\r
+               if (indexPosition < otherIndexPosition)\r
+                       return -1;\r
+\r
+               if (indexPosition > otherIndexPosition)\r
+                       return 1;\r
+\r
+               // initialize these flags as if they are for "in" operator, then\r
+               // change them if they are not\r
+               //\r
+               boolean thisIsEquals = false, otherIsEquals = false;\r
+               boolean thisIsNotEquals = true, otherIsNotEquals = true;\r
+\r
+               /* The call to "isRelationalOpPredicate()" will return false\r
+                * for a "probe predicate" because a probe predicate is really\r
+                * a disguised IN list. But when it comes to sorting, the probe\r
+                * predicate (which is of the form "<col> = ?") should be treated\r
+                * as an equality--i.e. it should have precedence over any non-\r
+                * equals predicate, per the comment at the start of this\r
+                * method.  So that's what we're checking here.\r
+                */\r
+               if (this.isRelationalOpPredicate() || // this is not "in" or\r
+                       this.isInListProbePredicate())    // this is a probe predicate\r
+               {\r
+                       int thisOperator = ((RelationalOperator)andNode.getLeftOperand()).getOperator();\r
+                       thisIsEquals = (thisOperator == RelationalOperator.EQUALS_RELOP ||\r
+                                                               thisOperator == RelationalOperator.IS_NULL_RELOP);\r
+                       thisIsNotEquals = (thisOperator == RelationalOperator.NOT_EQUALS_RELOP ||\r
+                                                                  thisOperator == RelationalOperator.IS_NOT_NULL_RELOP);\r
+               }\r
+\r
+               if (otherPred.isRelationalOpPredicate() || // other is not "in" or\r
+                       otherPred.isInListProbePredicate())    // other is a probe predicate\r
+               {\r
+                       int     otherOperator = ((RelationalOperator)(otherPred.getAndNode().getLeftOperand())).getOperator();\r
+                       otherIsEquals = (otherOperator == RelationalOperator.EQUALS_RELOP ||\r
+                                                                otherOperator == RelationalOperator.IS_NULL_RELOP);\r
+                       otherIsNotEquals = (otherOperator == RelationalOperator.NOT_EQUALS_RELOP ||\r
+                                                                otherOperator == RelationalOperator.IS_NOT_NULL_RELOP);\r
+               }\r
+\r
+               boolean thisIsBefore = (thisIsEquals && ! otherIsEquals) || ( ! thisIsNotEquals && otherIsNotEquals);\r
+               if (thisIsBefore)\r
+                       return -1;\r
+\r
+               boolean otherIsBefore = (otherIsEquals && ! thisIsEquals) || ( ! otherIsNotEquals && thisIsNotEquals);\r
+               if (otherIsBefore)\r
+                       return 1;\r
+               return 0;\r
+       }\r
+\r
+       /**\r
+        * Return the andNode.\r
+        *\r
+        * @return AndNode      The andNode.\r
+        */\r
+       public AndNode getAndNode()\r
+       {\r
+               return andNode;\r
+       }\r
+\r
+       /**\r
+        * Set the andNode.\r
+        *\r
+        * @param andNode       The new andNode.\r
+        */\r
+       public void setAndNode(AndNode andNode)\r
+       {\r
+               this.andNode = andNode;\r
+       }\r
+\r
+       /**\r
+        * Return the pushable.\r
+        *\r
+        * @return boolean      Whether or not the predicate is pushable.\r
+        */\r
+       public boolean getPushable()\r
+       {\r
+               return pushable;\r
+       }\r
+\r
+       /**\r
+        * Set whether or not this predicate is pushable.  This method\r
+        * is intended for use when creating a copy of the predicate, ex\r
+        * for predicate pushdown.  We choose not to add this assignment\r
+        * to copyFields() because the comments for that method say that\r
+        * it should copy all fields _except_ the two specified at init\r
+        * time; "pushable" is one of the two specified at init time.\r
+        *\r
+        * @param pushable Whether or not the predicate is pushable.\r
+        */\r
+       public void setPushable(boolean pushable) {\r
+               this.pushable = pushable;\r
+       }\r
+\r
+       /**\r
+        * Return the referencedSet.\r
+        *\r
+        * @return JBitSet      The referencedSet.\r
+        */\r
+       public JBitSet getReferencedSet()\r
+       {\r
+               return referencedSet;\r
+       }\r
+\r
+       /**\r
+        * Set the equivalence class, if any, for this predicate.\r
+        *\r
+        * @param equivalenceClass      The equivalence class for this predicate.\r
+        */\r
+       void setEquivalenceClass(int equivalenceClass)\r
+       {\r
+               this.equivalenceClass = equivalenceClass;\r
+       }\r
+\r
+       /**\r
+        * Get the equivalenceClass for this predicate.\r
+        *\r
+        * @return The equivalenceClass for this predicate.\r
+        */\r
+       int getEquivalenceClass()\r
+       {\r
+               return equivalenceClass;\r
+       }\r
+\r
+       /**\r
+        * Categorize this predicate.  Initially, this means\r
+        * building a bit map of the referenced tables for each predicate.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void categorize() throws StandardException\r
+       {\r
+               pushable = andNode.categorize(referencedSet, false);\r
+       }\r
+\r
+       /**\r
+        * Get the RelationalOperator on the left side of the AND node, if\r
+        * there is one.  If the left side is not a RelationalOperator, return\r
+        * null.\r
+        *\r
+        * @return      The RelationalOperator on the left side of the AND node,\r
+        *                      if any.\r
+        */\r
+       public RelationalOperator getRelop()\r
+       {\r
+               \r
+               if (andNode.getLeftOperand() instanceof RelationalOperator)\r
+               {\r
+                       return (RelationalOperator) andNode.getLeftOperand();\r
+               }\r
+               else\r
+               {\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       public final boolean isOrList()\r
+    {\r
+        return(andNode.getLeftOperand() instanceof OrNode);\r
+    }\r
+\r
+    /**\r
+     * Is this predicate a possible Qualifier for store?\r
+     * <p>\r
+     * Current 2 types of predicates can be pushed to store: \r
+     *   1) RelationalOperator - \r
+     *      represented with by left operand as instance of RelationalOperator.\r
+     *   2) A single And'd term of a list of OR terms\r
+     *      represented by left operand as instance of OrNode.\r
+     *\r
+     * More checking specific operator's terms to see if they are finally\r
+     * pushable to store.  In the final push at execution each term of the AND \r
+     * or OR must be a Relational operator with a column reference on one side \r
+     * and a constant on the other.\r
+     *\r
+     *\r
+        * @return true if term is wither a AND of a RelationalOperator, or an\r
+     *              OR of one or more Relational Operators.\r
+     *\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       public final boolean isStoreQualifier()\r
+    {\r
+               if ((andNode.getLeftOperand() instanceof RelationalOperator) ||\r
+                   (andNode.getLeftOperand() instanceof OrNode))\r
+               {\r
+            return(true);\r
+               }\r
+               else\r
+               {\r
+            return(false);\r
+               }\r
+    }\r
+\r
+    /**\r
+     * Is this predicate an pushable OR list?\r
+     * <p>\r
+     * Does the predicate represent a AND'd list of OR term's, all of which\r
+     * are pushable.  To be pushable each of OR terms must be a legal \r
+     * qualifier, which is a column reference on one side of a Relational\r
+     * operator and a constant on the other.\r
+     *\r
+        * @return true if the predicate is a pushable set of OR clauses.\r
+     *\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       public final boolean isPushableOrClause(Optimizable optTable)\r
+        throws StandardException\r
+       {\r
+        boolean ret_val = true;\r
+\r
+        if (andNode.getLeftOperand() instanceof OrNode)\r
+        {\r
+            QueryTreeNode node = andNode.getLeftOperand();\r
+\r
+            while (node instanceof OrNode)\r
+            {\r
+                OrNode or_node = (OrNode) node;\r
+\r
+                if (or_node.getLeftOperand() instanceof RelationalOperator)\r
+                {\r
+                    // if any term of the OR clause is not a qualifier, then\r
+                    // reject the entire OR clause.\r
+                    if (!((RelationalOperator) or_node.getLeftOperand()).\r
+                        isQualifier(optTable, true))\r
+                    {\r
+                        // one of the terms is not a pushable Qualifier.\r
+                        return(false);\r
+                    }\r
+\r
+                    node = or_node.getRightOperand();\r
+                }\r
+                else\r
+                {\r
+                    // one of the terms is not a RelationalOperator\r
+\r
+                    return(false);\r
+                }\r
+            }\r
+\r
+            return(true);\r
+        }\r
+        else\r
+        {\r
+            // Not an OR list\r
+            return(false);\r
+        }\r
+       }\r
+\r
+       /**\r
+        * Return whether or not this predicate has been used\r
+        * to add a new search clause of the specified type via transitive closure.\r
+        * NOTE: This can only be true if this is an equijoin\r
+        * between 2 column references.\r
+        *\r
+        * @param ro    The search clause that we are currently considering\r
+        *                              as the source for transitive closure\r
+        *\r
+        * @return      Whether or not this predicate has been used\r
+        *                      to add a new search clause of the specified type via transitive \r
+     *                 closure.\r
+        */\r
+       boolean transitiveSearchClauseAdded(RelationalOperator ro)\r
+       {\r
+               if (searchClauseHT == null || \r
+                       searchClauseHT.get(new Integer(ro.getOperator())) == null)\r
+               {\r
+                       return false;\r
+               }\r
+               else\r
+               {\r
+                       return true;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Mark this predicate as having been used to add a new predicate\r
+        * of the specified type via transitive closure on search clauses.\r
+        *\r
+        * @param ro    The search clause that we are currently considering\r
+        *                              as the source for transitive closure\r
+        *\r
+        */\r
+       void setTransitiveSearchClauseAdded(RelationalOperator ro)\r
+       {\r
+               if (searchClauseHT == null)\r
+               {\r
+                       searchClauseHT = new Hashtable();\r
+               }\r
+               /* I have to remember that this ro has been added to this predicate as a\r
+                * transitive search clause.\r
+                */\r
+               Integer i = new Integer(ro.getOperator());\r
+               searchClauseHT.put(i, i);\r
+       }\r
+\r
+       /**\r
+        * Get the start operator for this predicate for a scan.\r
+        *\r
+        * @param optTable      The optimizable table, so we can tell which side of\r
+        *                                      the operator the search column is on.\r
+        *\r
+        * @return      The start operator for a start key on this column.\r
+        */\r
+       int getStartOperator(Optimizable optTable)\r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(startKey, "Getting a start operator from a Predicate that's not a start key.");\r
+               }\r
+\r
+               /* if it's for "in" operator's dynamic start key, operator is GE,\r
+                * beetle 3858\r
+                */\r
+               if (andNode.getLeftOperand() instanceof InListOperatorNode)\r
+                       return ScanController.GE;\r
+\r
+               return getRelop().getStartOperator(optTable);\r
+       }\r
+\r
+       int getStopOperator(Optimizable optTable)\r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(stopKey, "Getting a stop operator from a Predicate that's not a stop key.");\r
+               }\r
+\r
+                /* if it's for "in" operator's dynamic stop key, operator is GT,\r
+                 * beetle 3858\r
+                 */\r
+               if (andNode.getLeftOperand() instanceof InListOperatorNode)\r
+                       return ScanController.GT;\r
+\r
+               return getRelop().getStopOperator(optTable);\r
+       }\r
+\r
+       /**\r
+        * Set the position of the index column that this predicate restricts\r
+        *\r
+        * @param indexPosition The position of the index column that this\r
+        *                                              predicate restricts.\r
+        */\r
+       void setIndexPosition(int indexPosition)\r
+       {\r
+               this.indexPosition = indexPosition;\r
+       }\r
+\r
+       /**\r
+        * Clear the start/stop position and qualifier flags\r
+        */\r
+       void clearScanFlags()\r
+       {\r
+               startKey = false;\r
+               stopKey = false;\r
+               isQualifier = false;\r
+       }\r
+\r
+       /**\r
+        * Clear the qualifier flag.\r
+        */\r
+       void clearQualifierFlag()\r
+       {\r
+               isQualifier = false;\r
+       }\r
+\r
+       void generateExpressionOperand(Optimizable optTable,\r
+                                                                               int columnPosition,\r
+                                                                               ExpressionClassBuilder acb,\r
+                                                                               MethodBuilder mb)\r
+                               throws StandardException\r
+       {\r
+               getRelop().generateExpressionOperand(optTable,\r
+                                                                                                       columnPosition,\r
+                                                                                                       acb,\r
+                                                                                                       mb);\r
+       }\r
+\r
+       void generateAbsoluteColumnId(MethodBuilder mb,\r
+                                                                               Optimizable optTable)\r
+       {\r
+               getRelop().generateAbsoluteColumnId(mb, optTable);\r
+       }\r
+\r
+       void generateRelativeColumnId(MethodBuilder mb,\r
+                                                                               Optimizable optTable)\r
+       {\r
+               getRelop().generateRelativeColumnId(mb, optTable);\r
+       }\r
+\r
+       void generateOperator(MethodBuilder mb,\r
+                                                               Optimizable optTable)\r
+       {\r
+               getRelop().generateOperator(mb, optTable);\r
+       }\r
+\r
+       void generateQualMethod(ExpressionClassBuilder acb,\r
+                                                               MethodBuilder mb,\r
+                                                               Optimizable optTable)\r
+                                       throws StandardException\r
+       {\r
+               getRelop().generateQualMethod(acb, mb, optTable);\r
+       }\r
+\r
+       void generateOrderedNulls(MethodBuilder mb)\r
+       {\r
+               getRelop().generateOrderedNulls(mb);\r
+       }\r
+\r
+       void generateNegate(MethodBuilder mb,\r
+                                                               Optimizable optTable)\r
+       {\r
+               getRelop().generateNegate(mb, optTable);\r
+       }\r
+\r
+       void generateOrderableVariantType(MethodBuilder mb,\r
+                                                               Optimizable optTable)\r
+                                       throws StandardException\r
+       {\r
+               int variantType = getRelop().getOrderableVariantType(optTable);\r
+               mb.push(variantType);\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 binaryRelOpColRefsToString() + "\nreferencedSet: " +\r
+                               referencedSet  + "\n" + "pushable: " + pushable + "\n" +\r
+                               super.toString();\r
+               }\r
+               else\r
+               {\r
+                       return "";\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Get a string version of the column references for this predicate\r
+        * IF it's a binary relational operator.  We only print out the\r
+        * names of the operands if they are column references; otherwise\r
+        * we just print a dummy value.  This is for debugging purposes\r
+        * only--it's a convenient way to see what columns the predicate\r
+        * is referencing, especially when tracing through code and printing\r
+        * assert failure.\r
+        */\r
+       public String binaryRelOpColRefsToString()\r
+       {\r
+               // We only consider binary relational operators here.\r
+               if (!(getAndNode().getLeftOperand()\r
+                       instanceof BinaryRelationalOperatorNode))\r
+               {\r
+                       return "";\r
+               }\r
+\r
+               final String DUMMY_VAL = "<expr>";\r
+               java.lang.StringBuffer sBuf = new java.lang.StringBuffer();\r
+               BinaryRelationalOperatorNode opNode =\r
+                       (BinaryRelationalOperatorNode)getAndNode().getLeftOperand();\r
+\r
+               // Get left operand's name.\r
+               if (opNode.getLeftOperand() instanceof ColumnReference)\r
+               {\r
+                       sBuf.append(\r
+                               ((ColumnReference)opNode.getLeftOperand()).getTableName() +\r
+                               "." +\r
+                               ((ColumnReference)opNode.getLeftOperand()).getColumnName()\r
+                       );\r
+               }\r
+               else\r
+                       sBuf.append(DUMMY_VAL);\r
+\r
+               // Get the operator type.\r
+               sBuf.append(" " + opNode.operator + " ");\r
+\r
+               // Get right operand's name.\r
+               if (opNode.getRightOperand() instanceof ColumnReference) {\r
+                       sBuf.append(\r
+                               ((ColumnReference)opNode.getRightOperand()).getTableName() +\r
+                               "." +\r
+                               ((ColumnReference)opNode.getRightOperand()).getColumnName()\r
+                       );\r
+               }\r
+               else\r
+                       sBuf.append(DUMMY_VAL);\r
+\r
+               return sBuf.toString();\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
+                       printLabel(depth, "andNode: ");\r
+                       andNode.treePrint(depth + 1);\r
+                       super.printSubNodes(depth);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Accept a visitor, and call v.visit()\r
+        * on child nodes as necessary.  \r
+        * \r
+        * @param v the visitor\r
+        *\r
+        * @exception StandardException on error\r
+        */\r
+       public Visitable accept(Visitor v) \r
+               throws StandardException\r
+       {\r
+               if (v.skipChildren(this))\r
+               {\r
+                       return v.visit(this);\r
+               }\r
+\r
+               Visitable returnNode = super.accept(v);\r
+\r
+               if (andNode != null && !v.stopTraversal())\r
+               {\r
+                       andNode = (AndNode)andNode.accept(v);\r
+               }\r
+\r
+               return returnNode;\r
+       }\r
+\r
+       /**\r
+        * Copy all fields of this Predicate (except the two that\r
+        * are set from 'init').\r
+        *\r
+        */\r
+\r
+       public void copyFields(Predicate otherPred) {\r
+\r
+               this.equivalenceClass = otherPred.getEquivalenceClass();\r
+               this.indexPosition = otherPred.getIndexPosition();\r
+               this.startKey = otherPred.isStartKey();\r
+               this.stopKey = otherPred.isStopKey();\r
+               this.isQualifier = otherPred.isQualifier();\r
+               this.searchClauseHT = otherPred.getSearchClauseHT();\r
+\r
+       }\r
+\r
+       /**\r
+        * Get the search clause Hash Table.\r
+        */\r
+\r
+       public Hashtable getSearchClauseHT() {\r
+               return searchClauseHT;\r
+       }\r
+\r
+       /**\r
+        * Determine whether or not this predicate is eligible for\r
+        * push-down into subqueries.  Right now the only predicates\r
+        * we consider to be eligible are those which 1) are Binary\r
+        * Relational operator nodes and 2) have a column reference\r
+        * on BOTH sides, each of which has a reference to a base\r
+        * table somewhere beneath it.\r
+        *\r
+        * @return Whether or not this predicate is eligible to be\r
+        *  pushed into subqueries.\r
+        */\r
+       protected boolean pushableToSubqueries()\r
+               throws StandardException\r
+       {\r
+               if (!isJoinPredicate())\r
+                       return false;\r
+\r
+               // Make sure both column references ultimately point to base\r
+               // tables.  If, for example, either column reference points to a\r
+               // a literal or an aggregate, then we do not push the predicate.\r
+               // This is because pushing involves remapping the references--\r
+               // but if the reference doesn't have a base table beneath it,\r
+               // the notion of "remapping" it doesn't (seem to) apply.  RESOLVE:\r
+               // it might be okay to make the "remap" operation a no-op for\r
+               // such column references, but it's not clear whether that's\r
+               // always a safe option; further investigation required.\r
+\r
+               BinaryRelationalOperatorNode opNode =\r
+                       (BinaryRelationalOperatorNode)getAndNode().getLeftOperand();\r
+\r
+               JBitSet tNums = new JBitSet(getReferencedSet().size());\r
+               BaseTableNumbersVisitor btnVis = new BaseTableNumbersVisitor(tNums);\r
+               opNode.getLeftOperand().accept(btnVis);\r
+               if (tNums.getFirstSetBit() == -1)\r
+                       return false;\r
+\r
+               tNums.clearAll();\r
+               opNode.getRightOperand().accept(btnVis);\r
+               if (tNums.getFirstSetBit() == -1)\r
+                       return false;\r
+\r
+               return true;\r
+       }\r
+\r
+       /**\r
+        * Is this predicate a join predicate?  In order to be so,\r
+        * it must be a binary relational operator node that has\r
+        * a column reference on both sides.\r
+        *\r
+        * @return Whether or not this is a join predicate.\r
+        */\r
+       protected boolean isJoinPredicate()\r
+       {\r
+               // If the predicate isn't a binary relational operator,\r
+               // then it's not a join predicate.\r
+               if (!(getAndNode().getLeftOperand()\r
+                       instanceof BinaryRelationalOperatorNode))\r
+               {\r
+                       return false;\r
+               }\r
+\r
+               BinaryRelationalOperatorNode opNode =\r
+                       (BinaryRelationalOperatorNode)getAndNode().getLeftOperand();\r
+\r
+               // If both sides are column references AND they point to different\r
+               // tables, then this is a join pred.\r
+               return ((opNode.getLeftOperand() instanceof ColumnReference) &&\r
+                       (opNode.getRightOperand() instanceof ColumnReference) &&\r
+                       (((ColumnReference)opNode.getLeftOperand()).getTableNumber() !=\r
+                       ((ColumnReference)opNode.getRightOperand()).getTableNumber()));\r
+       }\r
+\r
+       /**\r
+        * If this predicate's operator is a BinaryRelationalOperatorNode,\r
+        * then look at the operands and return a new, equivalent predicate\r
+        * that is "scoped" to the received ResultSetNode.  By "scoped" we\r
+        * mean that the operands, which shold be column references, have been\r
+        * mapped to the appropriate result columns in the received RSN.\r
+        * This is useful for pushing predicates from outer queries down\r
+        * into inner queries, in which case the column references need\r
+        * to be remapped.\r
+        *\r
+        * For example, let V1 represent\r
+        *\r
+        *    select i,j from t1 UNION select i,j from t2\r
+        * \r
+        * and V2 represent\r
+        *\r
+        *    select a,b from t3 UNION select a,b from t4\r
+        * \r
+        * Then assume we have the following query:\r
+        *\r
+        *    select * from V1, V2 where V1.j = V2.b\r
+        *\r
+        * Let's further assume that this Predicate object represents the\r
+        * "V1.j = V2.b" operator and that the childRSN we received\r
+        * as a parameter represents one of the subqueries to which we\r
+        * want to push the predicate; let's say it's:\r
+        *\r
+        *    select i,j from t1\r
+        *\r
+        * Then this method will return a new predicate whose binary\r
+        * operator represents the expression "T1.j = V2.b" (that is, V1.j\r
+        * will be mapped to the corresponding column in T1).  For more on\r
+        * how that mapping is made, see the "getScopedOperand()" method\r
+        * in BinaryRelationalOperatorNode.java.\r
+        *\r
+        * ASSUMPTION: We should only get to this method if we know that\r
+        * at least one operand in this predicate can and should be mapped\r
+        * to the received childRSN.  For an example of where that check is\r
+        * made, see the pushOptPredicate() method in SetOperatorNode.java.\r
+        *\r
+        * @param parentRSNsTables Set of all table numbers referenced by\r
+        *  the ResultSetNode that is _parent_ to the received childRSN.\r
+        *  We need this to make sure we don't scope the operands to a\r
+        *  ResultSetNode to which they don't apply.\r
+        * @param childRSN The result set node for which we want to create\r
+        *  a scoped predicate.\r
+        * @param whichRC If not -1 then this tells us which ResultColumn\r
+        *  in the received childRSN we need to use for the scoped predicate;\r
+        *  if -1 then the column position of the scoped column reference\r
+        *  will be stored in this array and passed back to the caller.\r
+        * @return A new predicate whose operands have been scoped to the\r
+        *  received childRSN.\r
+        */\r
+       protected Predicate getPredScopedForResultSet(\r
+               JBitSet parentRSNsTables, ResultSetNode childRSN,\r
+               int [] whichRC) throws StandardException\r
+       {\r
+               // We only deal with binary relational operators here.\r
+               if (!(getAndNode().getLeftOperand()\r
+                       instanceof BinaryRelationalOperatorNode))\r
+               {\r
+                       return this;\r
+               }\r
+\r
+               // The predicate must have an AndNode in CNF, so we\r
+               // need to create an AndNode representing:\r
+               //    <scoped_bin_rel_op> AND TRUE\r
+               // First create the boolean constant for TRUE.\r
+               ValueNode trueNode = (ValueNode) getNodeFactory().getNode(\r
+                       C_NodeTypes.BOOLEAN_CONSTANT_NODE,\r
+                       Boolean.TRUE,\r
+                       getContextManager());\r
+\r
+               BinaryRelationalOperatorNode opNode =\r
+                       (BinaryRelationalOperatorNode)getAndNode().getLeftOperand();\r
+\r
+               // Create a new op node with left and right operands that point\r
+               // to the received result set's columns as appropriate.\r
+               BinaryRelationalOperatorNode newOpNode = \r
+                       (BinaryRelationalOperatorNode) getNodeFactory().getNode(\r
+                               opNode.getNodeType(),\r
+                               opNode.getScopedOperand(\r
+                                       BinaryRelationalOperatorNode.LEFT,\r
+                                       parentRSNsTables,\r
+                                       childRSN,\r
+                                       whichRC),\r
+                               opNode.getScopedOperand(\r
+                                       BinaryRelationalOperatorNode.RIGHT,\r
+                                       parentRSNsTables,\r
+                                       childRSN,\r
+                                       whichRC),\r
+                               getContextManager());\r
+\r
+               // Bind the new op node.\r
+               newOpNode.bindComparisonOperator();\r
+\r
+               // Create and bind a new AND node in CNF form,\r
+               // i.e. "<newOpNode> AND TRUE".\r
+               AndNode newAnd = (AndNode) getNodeFactory().getNode(\r
+                       C_NodeTypes.AND_NODE,\r
+                       newOpNode,\r
+                       trueNode,\r
+                       getContextManager());\r
+               newAnd.postBindFixup();\r
+\r
+               // Categorize the new AND node; among other things, this\r
+               // call sets up the new operators's referenced table map,\r
+               // which is important for correct pushing of the new\r
+               // predicate.\r
+               JBitSet tableMap = new JBitSet(\r
+                       childRSN.getReferencedTableMap().size());\r
+               newAnd.categorize(tableMap, false);\r
+\r
+               // Now put the pieces together to get a new predicate.\r
+               Predicate newPred = (Predicate) getNodeFactory().getNode(\r
+                       C_NodeTypes.PREDICATE,\r
+                       newAnd,\r
+                       tableMap,\r
+                       getContextManager());\r
+\r
+               // Copy all of this predicates other fields into the new predicate.\r
+               newPred.clearScanFlags();\r
+               newPred.copyFields(this);\r
+               newPred.setPushable(getPushable());\r
+\r
+               // Take note of the fact that the new predicate is scoped for\r
+               // the sake of pushing; we need this information during optimization\r
+               // to figure out what we should and should not "pull" back up.\r
+               newPred.markAsScopedForPush();\r
+               return newPred;\r
+       }\r
+\r
+       /**\r
+        * Indicate that this predicate is a scoped copy of some other\r
+        * predicate (i.e. it was created as the result of a call to\r
+        * getPredScopedForResultSet() on some other predicate).\r
+        */\r
+       protected void markAsScopedForPush() {\r
+               this.scoped = true;\r
+       }\r
+\r
+       /**\r
+        * Return whether or not this predicate is a scoped copy of\r
+        * another predicate.\r
+        */\r
+       protected boolean isScopedForPush() {\r
+               return scoped;\r
+       }\r
+\r
+       /**\r
+        * When remapping a "normal" (i.e. non-scoped) predicate both\r
+        * of the predicate's operands are remapped and that's it.\r
+        * But when remapping a scoped predicate, things are slightly\r
+        * different.  This method handles remapping of scoped predicates.\r
+        *\r
+        * We know that, for a scoped predicate, exactly one operand has\r
+        * been scoped for a specific target result set; the other operand\r
+        * is pointing to some other instance of FromTable with which the\r
+        * target result set is to be joined (see getScopedOperand() in\r
+        * BinaryRelationalOperatorNode.java).  For every level of the\r
+        * query through which the scoped predicate is pushed, we have\r
+        * to perform a remap operation of the scoped operand.  We do\r
+        * *not*, however, remap the non-scoped operand.  The reason\r
+        * is that the non-scoped operand is already pointing to the\r
+        * result set against which it must be evaluated.  As the scoped\r
+        * predicate is pushed down the query tree, the non-scoped\r
+        * operand should not change where it's pointing and thus should\r
+        * not be remapped.  For example, assume we have a query whose\r
+        * tree has the following form:\r
+        *\r
+        *               SELECT[0] \r
+        *                /     \ \r
+        *              PRN      PRN \r
+        *               |        |\r
+        *          SELECT[4]   UNION\r
+        *           |           /   \ \r
+        *          PRN     SELECT[1]  SELECT[2] \r
+        *           |         |          | \r
+        *       <FBT:T1>     PRN        PRN \r
+        *                     |          |\r
+        *                SELECT[3]  <FromBaseTable:T2> \r
+        *                     |\r
+        *                    PRN\r
+        *                     |\r
+        *             <FromBaseTable:T3>\r
+        *\r
+        * Assume also that we have some predicate "SELECT[4].i = <UNION>.j".\r
+        * If the optimizer decides to push the predicate to the UNION\r
+        * node, it (the predicate) will be scoped to the UNION's children,\r
+        * yielding something like "SELECT[4].i = SELECT[1].j" for the\r
+        * left child and "SELECT[4].i = SELECT[2].j" for the right child.\r
+        * These scoped predicates will then be pushed to the PRNs above\r
+        * SELECT[3] and T2, respectively.  As part of that pushing\r
+        * process a call to PRN.pushOptPredicate() will occur, which\r
+        * brings us to this method.  So let's assume we're here for\r
+        * the scoped predicate "SELECT[4].i = SELECT[1].j".  Then we want\r
+        * to remap the scoped operand, "SELECT[1].j", so that it will\r
+        * point to the correct column in "SELECT[3]".  We do NOT, however,\r
+        * want to remap the non-scoped operand "SELECT[4].i" because that\r
+        * operand is already pointing to the correct result set--namely,\r
+        * to a column in SELECT[4].  That non-scoped operand should not\r
+        * change regardless of how far down the UNION subtree the scoped\r
+        * predicate is pushed.\r
+        * \r
+        * If we did try to remap the non-scoped operand, it would end up\r
+        * pointing to result sets too low in the tree, which could lead to\r
+        * execution-time errors.  So when we remap a scoped predicate, we\r
+        * have to make sure we only remap the scoped operand.  That's what\r
+        * this method does.\r
+        *\r
+        * @return True if this predicate is a scoped predicate, in which\r
+        *  case we performed a one-sided remap.  False if the predicate is\r
+        *  not scoped; the caller can then make the calls to perform a\r
+        *  "normal" remap on this predicate.\r
+        */\r
+       protected boolean remapScopedPred()\r
+       {\r
+               if (!scoped)\r
+                       return false;\r
+\r
+               /* Note: right now the only predicates we scope are those\r
+                * which are join predicates and all scoped predicates will\r
+                * have the same relational operator as the predicates from\r
+                * which they were scoped.  Thus if we get here, we know\r
+                * that andNode's leftOperand must be an instance of\r
+                * BinaryRelationalOperatorNode (and therefore the following\r
+                * cast is safe).\r
+                */\r
+               BinaryRelationalOperatorNode binRelOp =\r
+                       (BinaryRelationalOperatorNode)andNode.getLeftOperand();\r
+\r
+               ValueNode operand = null;\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       /* If this predicate is scoped then one (and only one) of\r
+                        * its operands should be scoped.  Note that it's possible\r
+                        * for an operand to be scoped to a non-ColumnReference\r
+                        * value; if either operand is not a ColumnReference, then\r
+                        * that operand must be the scoped operand.\r
+                        */\r
+                       operand = binRelOp.getLeftOperand();\r
+                       boolean leftIsScoped =\r
+                               !(operand instanceof ColumnReference) ||\r
+                                       ((ColumnReference)operand).isScoped();\r
+\r
+                       operand = binRelOp.getRightOperand();\r
+                       boolean rightIsScoped =\r
+                               !(operand instanceof ColumnReference) ||\r
+                                       ((ColumnReference)operand).isScoped();\r
+\r
+                       SanityManager.ASSERT(leftIsScoped ^ rightIsScoped,\r
+                               "All scoped predicates should have exactly one scoped " +\r
+                               "operand, but '" + binaryRelOpColRefsToString() +\r
+                               "' has " + (leftIsScoped ? "TWO" : "NONE") + ".");\r
+               }\r
+\r
+               // Find the scoped operand and remap it.\r
+               operand = binRelOp.getLeftOperand();\r
+               if ((operand instanceof ColumnReference) &&\r
+                       ((ColumnReference)operand).isScoped())\r
+               {\r
+                       // Left operand is the scoped operand.\r
+                       ((ColumnReference)operand).remapColumnReferences();\r
+               }\r
+               else\r
+               {\r
+                       operand = binRelOp.getRightOperand();\r
+                       if ((operand instanceof ColumnReference) &&\r
+                               ((ColumnReference)operand).isScoped())\r
+                       {\r
+                               // Right operand is the scoped operand.\r
+                               ((ColumnReference)operand).remapColumnReferences();\r
+                       }\r
+\r
+                       // Else scoped operand is not a ColumnReference, which\r
+                       // means it can't (and doesn't need to) be remapped. So\r
+                       // just fall through and return.\r
+               }\r
+\r
+               return true;\r
+       }\r
+\r
+       /**\r
+        * Return true if this predicate is scoped AND the scoped\r
+        * operand is a ColumnReference that points to a source result\r
+        * set.  If the scoped operand is not a ColumnReference that\r
+        * points to a source result set then it must be pointing to\r
+        * some kind of expression, such as a literal (ex. 'strlit'),\r
+        * an aggregate value (ex. "count(*)"), or the result of a\r
+        * function (ex. "sin(i)") or operator (ex. "i+1").\r
+        *\r
+        * This method is used when pushing predicates to determine how\r
+        * far down the query tree a scoped predicate needs to be pushed\r
+        * to allow for successful evaluation of the scoped operand.  If\r
+        * the scoped operand is not pointing to a source result set\r
+        * then it should not be pushed any further down tree.  The reason\r
+        * is that evaluation of the expression to which the operand is\r
+        * pointing may depend on other values from the current level\r
+        * in the tree (ex. "sin(i)" depends on the value of "i", which\r
+        * could be a column at the predicate's current level).  If we\r
+        * pushed the predicate further down, those values could become\r
+        * inaccessible, leading to execution-time errors.\r
+        *\r
+        * If, on the other hand, the scoped operand *is* pointing to\r
+        * a source result set, then we want to push it further down\r
+        * the tree until it reaches that result set, which allows\r
+        * evaluation of this predicate to occur as close to store as\r
+        * possible.  This method doesn't actually do the push, it just\r
+        * returns "true" and then the caller can push as appropriate.\r
+        */\r
+       protected boolean isScopedToSourceResultSet()\r
+               throws StandardException\r
+       {\r
+               if (!scoped)\r
+                       return false;\r
+\r
+               /* Note: right now the only predicates we scope are those\r
+                * which are join predicates and all scoped predicates will\r
+                * have the same relational operator as the predicates from\r
+                * which they were scoped.  Thus if we get here, we know\r
+                * that andNode's leftOperand must be an instance of\r
+                * BinaryRelationalOperatorNode (and therefore the following\r
+                * cast is safe).\r
+                */\r
+               BinaryRelationalOperatorNode binRelOp =\r
+                       (BinaryRelationalOperatorNode)andNode.getLeftOperand();\r
+\r
+               ValueNode operand = binRelOp.getLeftOperand();\r
+\r
+               /* If operand isn't a ColumnReference then is must be the\r
+                * scoped operand.  This is because both operands have to\r
+                * be column references in order for scoping to occur (as\r
+                * per pushableToSubqueries()) and only the scoped operand\r
+                * can change (esp. can become a non-ColumnReference) as\r
+                * part of the scoping process.  And since it's not a\r
+                * ColumnReference it can't be "a ColumnReference that\r
+                * points to a source result set", so return false.\r
+                */\r
+               if (!(operand instanceof ColumnReference))\r
+                       return false;\r
+\r
+               /* If the operand is a ColumnReference and is scoped,\r
+                * then see if it is pointing to a ResultColumn whose\r
+                * expression is either another a CR or a Virtual\r
+                * ColumnNode.  If it is then that operand applies\r
+                * to a source result set further down the tree and\r
+                * thus we return true.\r
+                */\r
+               ValueNode exp = null;\r
+               ColumnReference cRef = (ColumnReference)operand;\r
+               if (cRef.isScoped())\r
+               {\r
+                       exp = cRef.getSource().getExpression();\r
+                       return ((exp instanceof VirtualColumnNode) ||\r
+                               (exp instanceof ColumnReference));\r
+               }\r
+\r
+               operand = binRelOp.getRightOperand();\r
+               if (!(operand instanceof ColumnReference))\r
+                       return false;\r
+\r
+               cRef = (ColumnReference)operand;\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       // If we got here then the left operand was NOT the scoped\r
+                       // operand; make sure the right one is scoped, then.\r
+                       SanityManager.ASSERT(cRef.isScoped(),\r
+                               "All scoped predicates should have exactly one scoped " +\r
+                               "operand, but '" + binaryRelOpColRefsToString() +\r
+                               "has NONE.");\r
+               }\r
+\r
+               exp = cRef.getSource().getExpression();\r
+               return ((exp instanceof VirtualColumnNode) ||\r
+                       (exp instanceof ColumnReference));\r
+       }\r
+\r
+       /**\r
+        * Return whether or not this predicate corresponds to a legitimate\r
+        * relational operator.\r
+        *\r
+        * @return False if there is no relational operator for this predicate\r
+        *  OR if this predicate is an internal "probe predicate" (in which\r
+        *  case it "looks" like we have a relational operator but in truth\r
+        *  it's a disguised IN-list operator). True otherwise.\r
+        */\r
+       protected boolean isRelationalOpPredicate()\r
+       {\r
+               /* The isRelationalOperator() method on the ValueNode\r
+                * interface tells us what we need to know, so all we have\r
+                * to do is call that method on the left child of our AND node.\r
+                * Note that BinaryRelationalOperatorNode.isRelationalOperator()\r
+                * includes logic to determine whether or not it (the BRON) is\r
+                * really a disguised IN-list operator--and if so, it will\r
+                * return false (which is what we want).\r
+                */\r
+               return andNode.getLeftOperand().isRelationalOperator();\r
+       }\r
+\r
+       /**\r
+        * Return whether or not this predicate is an IN-list probe\r
+        * predicate.\r
+        */\r
+       protected boolean isInListProbePredicate()\r
+       {\r
+               /* The isInListProbeNode() method on the ValueNode interface\r
+                * tells us what we need to know, so all we have to do is call\r
+                * that method on the left child of our AND node.\r
+                */\r
+               return andNode.getLeftOperand().isInListProbeNode();\r
+       }\r
+\r
+       /**\r
+        * If this predicate corresponds to an IN-list, return the underlying\r
+        * InListOperatorNode from which it was built.  There are two forms\r
+        * to check for:\r
+        *\r
+        *  1. This predicate is an IN-list "probe predicate", in which case\r
+        *     the underlying InListOpNode is stored within the binary relational\r
+        *     operator that is the left operand of this predicate's AND node.\r
+        *\r
+        *  2. This predicate corresponds to an IN-list that could _not_ be\r
+        *     transformed into a "probe predicate" (i.e. the IN-list contains\r
+        *     one or more non-parameter, non-constant values). In that case\r
+        *     the underlying InListOpNode is simply the left operand of\r
+        *     this predicate's AND node.\r
+        *\r
+        * If this predicate does not correspond to an IN-list in any way,\r
+        * this method will return null.\r
+        */\r
+       protected InListOperatorNode getSourceInList()\r
+       {\r
+               return getSourceInList(false);\r
+       }\r
+\r
+       /**\r
+        * Does the work of getSourceInList() above, but can also be called\r
+        * directly with an argument to indicate whether or not we should\r
+        * limit ourselves to probe predicates.\r
+        *\r
+        * @param probePredOnly If true, only get the source IN list for this\r
+        *   predicate *if* it is an IN-list probe predicate.  If false,\r
+        *   return the underlying InListOperatorNode (if it exists) regardless\r
+        *   of whether this is a probe predicate or an un-transformed IN-list\r
+        *   pred.\r
+        * \r
+        * @return Underlying InListOp for this predicate (depending on\r
+        *   the value of probePredOnly), or null if this predicate does\r
+        *   not correspond to an IN-list in any way.\r
+        */\r
+       protected InListOperatorNode getSourceInList(boolean probePredOnly)\r
+       {\r
+               ValueNode vn = andNode.getLeftOperand();\r
+               if (isInListProbePredicate())\r
+                       return ((BinaryRelationalOperatorNode)vn).getInListOp();\r
+\r
+               if (probePredOnly)\r
+                       return null;\r
+\r
+               if (vn instanceof InListOperatorNode)\r
+                       return (InListOperatorNode)vn;\r
+\r
+               return null;\r
+       }\r
+}\r