Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / compile / UnaryOperatorNode.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java
new file mode 100644 (file)
index 0000000..db6ab4d
--- /dev/null
@@ -0,0 +1,842 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.UnaryOperatorNode\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.store.access.Qualifier;\r
+\r
+import org.apache.derby.iapi.sql.compile.Visitable;\r
+import org.apache.derby.iapi.sql.compile.Visitor;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.reference.ClassName;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+import org.apache.derby.iapi.services.compiler.LocalField;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\r
+\r
+import org.apache.derby.iapi.types.StringDataValue;\r
+import org.apache.derby.iapi.types.TypeId;\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.types.SqlXmlUtil;\r
+\r
+import java.lang.reflect.Modifier;\r
+import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;\r
+\r
+import org.apache.derby.iapi.util.JBitSet;\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+\r
+import java.sql.Types;\r
+import java.util.Vector;\r
+\r
+/**\r
+ * A UnaryOperatorNode represents a built-in unary operator as defined by\r
+ * the ANSI/ISO SQL standard.  This covers operators like +, -, NOT, and IS NULL.\r
+ * Java operators are not represented here: the JSQL language allows Java\r
+ * methods to be called from expressions, but not Java operators.\r
+ *\r
+ */\r
+\r
+public class UnaryOperatorNode extends ValueNode\r
+{\r
+       String  operator;\r
+       String  methodName;\r
+    \r
+    /**\r
+     * Operator type, only valid for XMLPARSE and XMLSERIALIZE.\r
+     */\r
+       private int operatorType;\r
+\r
+       String          resultInterfaceType;\r
+       String          receiverInterfaceType;\r
+\r
+       /**\r
+        * WARNING: operand may be NULL for COUNT(*).  \r
+        */\r
+       ValueNode       operand;\r
+\r
+       // At the time of adding XML support, it was decided that\r
+       // we should avoid creating new OperatorNodes where possible.\r
+       // So for the XML-related unary operators we just add the\r
+       // necessary code to _this_ class, similar to what is done in\r
+       // TernarnyOperatorNode. Subsequent unary operators (whether\r
+       // XML-related or not) should follow this example when\r
+       // possible.\r
+    //\r
+    // This has lead to this class having somewhat of\r
+    // a confused personality. In one mode it is really\r
+    // a parent (abstract) class for various unary operator\r
+    // node implementations, in its other mode it is a concrete\r
+    // class for XMLPARSE and XMLSERIALIZE.\r
+\r
+       public final static int XMLPARSE_OP = 0;\r
+       public final static int XMLSERIALIZE_OP = 1;\r
+\r
+       // NOTE: in the following 4 arrays, order\r
+       // IS important.\r
+\r
+       static final String[] UnaryOperators = {\r
+               "xmlparse",\r
+               "xmlserialize"\r
+       };\r
+\r
+       static final String[] UnaryMethodNames = {\r
+               "XMLParse",\r
+               "XMLSerialize"\r
+       };\r
+\r
+       static final String[] UnaryResultTypes = {\r
+               ClassName.XMLDataValue,                 // XMLParse\r
+               ClassName.StringDataValue               // XMLSerialize\r
+       };\r
+\r
+       static final String[] UnaryArgTypes = {\r
+               ClassName.StringDataValue,              // XMLParse\r
+               ClassName.XMLDataValue                  // XMLSerialize\r
+       };\r
+\r
+       // Array to hold Objects that contain primitive\r
+       // args required by the operator method call.\r
+       private Object [] additionalArgs;\r
+\r
+       // Class used to hold XML-specific objects required for\r
+       // parsing/serializing XML data.\r
+       private SqlXmlUtil sqlxUtil;\r
+\r
+       /**\r
+        * Initializer for a UnaryOperatorNode.\r
+        *\r
+        * <ul>\r
+        * @param operand       The operand of the node\r
+        * @param operatorOrOpType      Either 1) the name of the operator,\r
+        *  OR 2) an Integer holding the operatorType for this operator.\r
+        * @param methodNameOrAddedArgs Either 1) name of the method\r
+        *  to call for this operator, or 2) an array of Objects\r
+        *  from which primitive method parameters can be\r
+        *  retrieved.\r
+        */\r
+\r
+       public void init(\r
+                                       Object  operand,\r
+                                       Object          operatorOrOpType,\r
+                                       Object          methodNameOrAddedArgs)\r
+       {\r
+               this.operand = (ValueNode) operand;\r
+               if (operatorOrOpType instanceof String) {\r
+               // then 2nd and 3rd params are operator and methodName,\r
+               // respectively.\r
+                       this.operator = (String) operatorOrOpType;\r
+                       this.methodName = (String) methodNameOrAddedArgs;\r
+                       this.operatorType = -1;\r
+               }\r
+               else {\r
+               // 2nd and 3rd params are operatorType and additional args,\r
+               // respectively.\r
+                       if (SanityManager.DEBUG) {\r
+                               SanityManager.ASSERT(\r
+                                       ((operatorOrOpType instanceof Integer) &&\r
+                                               ((methodNameOrAddedArgs == null) ||\r
+                                               (methodNameOrAddedArgs instanceof Object[]))),\r
+                                       "Init params in UnaryOperator node have the " +\r
+                                       "wrong type.");\r
+                       }\r
+                       this.operatorType = ((Integer) operatorOrOpType).intValue();\r
+                       this.operator = UnaryOperators[this.operatorType];\r
+                       this.methodName = UnaryMethodNames[this.operatorType];\r
+                       this.resultInterfaceType = UnaryResultTypes[this.operatorType];\r
+                       this.receiverInterfaceType = UnaryArgTypes[this.operatorType];\r
+                       this.additionalArgs = (Object[])methodNameOrAddedArgs;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Initializer for a UnaryOperatorNode\r
+        *\r
+        * @param operand       The operand of the node\r
+        */\r
+       public void init(Object operand)\r
+       {\r
+               this.operand = (ValueNode) operand;\r
+               this.operatorType = -1;\r
+       }\r
+\r
+       /**\r
+        * Set the operator.\r
+        *\r
+        * @param operator      The operator.\r
+        */\r
+       void setOperator(String operator)\r
+       {\r
+               this.operator = operator;\r
+               this.operatorType = -1;\r
+       }\r
+\r
+       /**\r
+        * Get the operator of this unary operator.\r
+        *\r
+        * @return      The operator of this unary operator.\r
+        */\r
+       String getOperatorString()\r
+       {\r
+               return operator;\r
+       }\r
+\r
+       /**\r
+        * Set the methodName.\r
+        *\r
+        * @param methodName    The methodName.\r
+        */\r
+       void setMethodName(String methodName)\r
+       {\r
+               this.methodName = methodName;\r
+               this.operatorType = -1;\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 "operator: " + operator + "\n" +\r
+                               "methodName: " + methodName + "\n" +\r
+                               super.toString();\r
+               }\r
+               else\r
+               {\r
+                       return "";\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Prints the sub-nodes of this object.  See QueryTreeNode.java for\r
+        * how tree printing is supposed to work.\r
+        *\r
+        * @param depth         The depth of this node in the tree\r
+        */\r
+\r
+       public void printSubNodes(int depth)\r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       super.printSubNodes(depth);\r
+\r
+                       if (operand != null)\r
+                       {\r
+                               printLabel(depth, "operand: ");\r
+                               operand.treePrint(depth + 1);\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Get the operand of this unary operator.\r
+        *\r
+        * @return      The operand of this unary operator.\r
+        */\r
+       public ValueNode getOperand()\r
+       {\r
+               return operand;\r
+       }\r
+\r
+       /**\r
+        * Get the parameter operand of this unary operator.\r
+        * For the example below, for abs unary operator node, we want to get ?\r
+        * select * from t1 where -? = max_cni(abs(-?), sqrt(+?))\r
+        * \r
+        * This gets called when ParameterNode is needed to get parameter\r
+        * specific information like getDefaultValue(), getParameterNumber() etc \r
+        * \r
+        * @return      The parameter operand of this unary operator else null.\r
+        */\r
+       public ParameterNode getParameterOperand() throws StandardException\r
+       {\r
+               if (requiresTypeFromContext() == false)\r
+                       return null;\r
+               else {\r
+                       UnaryOperatorNode tempUON = this;\r
+                       while (!(tempUON.getOperand() instanceof ParameterNode)) \r
+                               tempUON = (UnaryOperatorNode)tempUON.getOperand();\r
+                       return (ParameterNode)(tempUON.getOperand());\r
+               }\r
+       }\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
+     * This method is the implementation for XMLPARSE and XMLSERIALIZE.\r
+     * Sub-classes need to implement their own bindExpression() method\r
+     * for their own specific rules.\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
+        * @return      The new top of the expression tree.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public ValueNode bindExpression(\r
+                                       FromList fromList, SubqueryList subqueryList,\r
+                                       Vector  aggregateVector)\r
+                               throws StandardException\r
+       {\r
+               bindOperand(fromList, subqueryList, aggregateVector);\r
+        if (operatorType == XMLPARSE_OP)\r
+            bindXMLParse();\r
+        else if (operatorType == XMLSERIALIZE_OP)\r
+            bindXMLSerialize();\r
+        return this;\r
+       }\r
+\r
+       /**\r
+        * Bind the operand for this unary operator.\r
+     * Binding the operator may change the operand node.\r
+     * Sub-classes bindExpression() methods need to call this\r
+     * method to bind the operand.\r
+        */\r
+       protected void bindOperand(\r
+                                       FromList fromList, SubqueryList subqueryList,\r
+                                       Vector  aggregateVector)\r
+                               throws StandardException\r
+       {\r
+               operand = operand.bindExpression(fromList, subqueryList,\r
+                                                               aggregateVector);\r
+\r
+               if (operand.requiresTypeFromContext()) {\r
+                       bindParameter();\r
+            // If not bound yet then just return.\r
+            // The node type will be set by either\r
+            // this class' bindExpression() or a by\r
+            // a node that contains this expression.\r
+            if (operand.getTypeServices() == null)\r
+                return;\r
+        }\r
+\r
+               /* If the operand is not a built-in type, then generate a bound conversion\r
+                * tree to a built-in type.\r
+                */\r
+               if (! (operand instanceof UntypedNullConstantNode) &&\r
+                       operand.getTypeId().userType() &&\r
+                       ! (this instanceof IsNullNode))\r
+               {\r
+                       operand = operand.genSQLJavaSQLTree();\r
+               }\r
+       }\r
+\r
+    /**\r
+     * Bind an XMLPARSE operator.  Makes sure the operand type\r
+     * is correct, and sets the result type.\r
+     *\r
+     * @exception StandardException Thrown on error\r
+     */\r
+    private void bindXMLParse() throws StandardException\r
+    {\r
+        // Check the type of the operand - this function is allowed only on\r
+        // string value (char) types.\r
+        TypeId operandType = operand.getTypeId();\r
+        if (operandType != null) {\r
+            switch (operandType.getJDBCTypeId())\r
+            {\r
+                case Types.CHAR:\r
+                case Types.VARCHAR:\r
+                case Types.LONGVARCHAR:\r
+                case Types.CLOB:\r
+                    break;\r
+                default:\r
+                {\r
+                    throw StandardException.newException(\r
+                        SQLState.LANG_UNARY_FUNCTION_BAD_TYPE, \r
+                        methodName,\r
+                        operandType.getSQLTypeName());\r
+                }\r
+            }\r
+        }\r
+\r
+        // Create a new XML compiler object; the constructor\r
+        // here automatically creates the XML-specific objects \r
+        // required for parsing/serializing XML, so all we\r
+        // have to do is create an instance.\r
+        sqlxUtil = new SqlXmlUtil();\r
+\r
+        // The result type of XMLParse() is always an XML type.\r
+        setType(DataTypeDescriptor.getBuiltInDataTypeDescriptor(\r
+            StoredFormatIds.XML_TYPE_ID));\r
+    }\r
+\r
+    /**\r
+     * Bind an XMLSERIALIZE operator.  Makes sure the operand type\r
+     * and target type are both correct, and sets the result type.\r
+     *\r
+     * @exception StandardException Thrown on error\r
+     */\r
+    private void bindXMLSerialize() throws StandardException\r
+    {\r
+        TypeId operandType;\r
+\r
+        // Check the type of the operand - this function is allowed only on\r
+        // the XML type.\r
+        operandType = operand.getTypeId();\r
+        if ((operandType != null) && !operandType.isXMLTypeId())\r
+        {\r
+            throw StandardException.newException(\r
+                SQLState.LANG_UNARY_FUNCTION_BAD_TYPE, \r
+                methodName,\r
+                operandType.getSQLTypeName());\r
+        }\r
+\r
+        // Check the target type.  We only allow string types to be used as\r
+        // the target type.  The targetType is stored as the first Object\r
+        // in our list of additional parameters, so we have to retrieve\r
+        // it from there.\r
+        if (SanityManager.DEBUG) {\r
+            SanityManager.ASSERT(\r
+                ((additionalArgs != null) && (additionalArgs.length > 0)),\r
+                "Failed to locate target type for XMLSERIALIZE operator");\r
+        }\r
+\r
+        DataTypeDescriptor targetType =\r
+            (DataTypeDescriptor)additionalArgs[0];\r
+\r
+        TypeId targetTypeId = targetType.getTypeId();\r
+        switch (targetTypeId.getJDBCTypeId())\r
+        {\r
+            case Types.CHAR:\r
+            case Types.VARCHAR:\r
+            case Types.LONGVARCHAR:\r
+            case Types.CLOB:\r
+                break;\r
+            default:\r
+            {\r
+                throw StandardException.newException(\r
+                    SQLState.LANG_INVALID_XMLSERIALIZE_TYPE,\r
+                    targetTypeId.getSQLTypeName());\r
+            }\r
+        }\r
+\r
+        // The result type of XMLSerialize() is always a string; which\r
+        // kind of string is determined by the targetType field.\r
+        setType(targetType);\r
+               //Set the collation type to be same as the current schema's \r
+               //collation type. \r
+        setCollationUsingCompilationSchema(\r
+                               StringDataValue.COLLATION_DERIVATION_IMPLICIT);\r
+    }\r
+\r
+       /**\r
+        * Preprocess an expression tree.  We do a number of transformations\r
+        * here (including subqueries, IN lists, LIKE and BETWEEN) plus\r
+        * subquery flattening.\r
+        * NOTE: This is done before the outer ResultSetNode is preprocessed.\r
+        *\r
+        * @param       numTables                       Number of tables in the DML Statement\r
+        * @param       outerFromList           FromList from outer query block\r
+        * @param       outerSubqueryList       SubqueryList from outer query block\r
+        * @param       outerPredicateList      PredicateList from outer query block\r
+        *\r
+        * @return              The modified expression\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public ValueNode preprocess(int numTables,\r
+                                                               FromList outerFromList,\r
+                                                               SubqueryList outerSubqueryList,\r
+                                                               PredicateList outerPredicateList) \r
+                                       throws StandardException\r
+       {\r
+               if (operand != null)\r
+               {\r
+                       operand = operand.preprocess(numTables,\r
+                                                                                outerFromList, outerSubqueryList,\r
+                                                                                outerPredicateList);\r
+               }\r
+               return this;\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
+        *\r
+        * @exception StandardException                 Thrown on error\r
+        */\r
+       public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)\r
+               throws StandardException\r
+       {\r
+               return (operand == null) ? \r
+                               false : \r
+                               operand.categorize(referencedTabs, simplePredsOnly);\r
+       }\r
+\r
+       /**\r
+        * Remap all ColumnReferences in this tree to be clones of the\r
+        * underlying expression.\r
+        *\r
+        * @return ValueNode                    The remapped expression tree.\r
+        *\r
+        * @exception StandardException                 Thrown on error\r
+        */\r
+       public ValueNode remapColumnReferencesToExpressions()\r
+               throws StandardException\r
+       {\r
+               if (operand != null)\r
+               {\r
+                       operand = operand.remapColumnReferencesToExpressions();\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
+               return (operand == null) ? true: operand.isConstantExpression();\r
+       }\r
+\r
+       /** @see ValueNode#constantExpression */\r
+       public boolean constantExpression(PredicateList whereClause)\r
+       {\r
+               return (operand == null) ?\r
+                                       true :\r
+                                       operand.constantExpression(whereClause);\r
+       }\r
+\r
+       /**\r
+        * By default unary operators don't accept ? parameters as operands.\r
+        * This can be over-ridden for particular unary operators.\r
+        *\r
+        *      We throw an exception if the parameter doesn't have a datatype\r
+        *      assigned to it yet.\r
+        *\r
+        * @exception StandardException         Thrown if ?  parameter doesn't\r
+        *                                                                      have a type bound to it yet.\r
+        *                                                                      ? parameter where it isn't allowed.\r
+        */\r
+\r
+       void bindParameter() throws StandardException\r
+       {\r
+               if (operatorType == XMLPARSE_OP)\r
+               {\r
+                       /* SQL/XML[2006] allows both binary and character strings for\r
+                        * the XMLParse parameter (section 10.16:Function).  The spec\r
+                        * also goes on to say, in section 6.15:Conformance Rules:4,\r
+                        * that:\r
+                        *\r
+                        * "Without Feature X066, XMLParse: BLOB input and DOCUMENT\r
+                        * option, in conforming SQL language, the declared type of\r
+                        * the <string value expression> immediately contained in\r
+                        * <XML parse> shall not be a binary string type."\r
+                        *\r
+                        * Thus since Derby doesn't currently support BLOB input,\r
+                        * we have to ensure that the "declared type" of the parameter\r
+                        * is not a binary string type; i.e. it must be a character\r
+                        * string type.  Since there's no way to determine what the\r
+                        * declared type is from the XMLPARSE syntax, the user must\r
+                        * explicitly declare the type of the parameter, and it must\r
+                        * be a character string. They way s/he does that is by\r
+                        * specifying an explicit CAST on the parameter, such as:\r
+                        *\r
+                        *  insert into myXmlTable (xcol) values\r
+                        *    XMLPARSE(DOCUMENT cast (? as CLOB) PRESERVE WHITESPACE);\r
+                        *\r
+                        * If that was done then we wouldn't be here; we only get\r
+                        * here if the parameter was specified without a cast.  That\r
+                        * means we don't know what the "declared type" is and so\r
+                        * we throw an error.\r
+                        */\r
+                       throw StandardException.newException(\r
+                               SQLState.LANG_XMLPARSE_UNKNOWN_PARAM_TYPE);\r
+               }\r
+               else if (operatorType == XMLSERIALIZE_OP) {\r
+        // For now, since JDBC has no type defined for XML, we\r
+        // don't allow binding to an XML parameter.\r
+               throw StandardException.newException(\r
+                  SQLState.LANG_ATTEMPT_TO_BIND_XML);\r
+               }\r
+               else if (operand.getTypeServices() == null)\r
+               {\r
+                       throw StandardException.newException(SQLState.LANG_UNARY_OPERAND_PARM, operator);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Do code generation for this unary operator.\r
+        *\r
+        * @param acb   The ExpressionClassBuilder for the class we're generating\r
+        * @param mb    The method the expression will go into\r
+        *\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public void generateExpression(ExpressionClassBuilder acb,\r
+                                                                                       MethodBuilder mb)\r
+                                                                       throws StandardException\r
+       {\r
+               // For XML operator we do some extra work.\r
+               boolean xmlGen = (operatorType == XMLPARSE_OP) ||\r
+                       (operatorType == XMLSERIALIZE_OP);\r
+\r
+               if (xmlGen) {\r
+               // We create an execution-time object from which we call\r
+               // the necessary methods.  We do this for two reasons: 1) this\r
+               // level of indirection allows us to separate the XML data type\r
+               // from the required XML implementation classes (esp. JAXP and\r
+               // Xalan classes)--for more on how this works, see the comments\r
+               // in SqlXmlUtil.java; and 2) this allows us to create the\r
+               // required XML objects a single time (which we did at bind time\r
+               // when we created a new SqlXmlUtil) and then reuse those objects\r
+               // for each row in the target result set, instead of creating\r
+               // new objects every time; see SqlXmlUtil.java for more.\r
+                       mb.pushNewStart(\r
+                               "org.apache.derby.impl.sql.execute.SqlXmlExecutor");\r
+                       mb.pushNewComplete(addXmlOpMethodParams(acb, mb));\r
+               }\r
+\r
+               String resultTypeName = \r
+                       (operatorType == -1)\r
+                               ? getTypeCompiler().interfaceName()\r
+                               : resultInterfaceType;\r
+                       \r
+               // System.out.println("resultTypeName " + resultTypeName + " method " + methodName);\r
+               // System.out.println("isBooleanTypeId() " + getTypeId().isBooleanTypeId());\r
+\r
+               boolean needField = !getTypeId().isBooleanTypeId();\r
+\r
+               String receiverType = getReceiverInterfaceName();\r
+               operand.generateExpression(acb, mb);\r
+               mb.cast(receiverType);\r
+\r
+               if (needField) {\r
+\r
+                       /* Allocate an object for re-use to hold the result of the operator */\r
+                       LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);\r
+                       mb.getField(field);\r
+\r
+                       /* If we're calling a method on a class (SqlXmlExecutor) instead\r
+                        * of calling a method on the operand interface, then we invoke\r
+                        * VIRTUAL; we then have 2 args (the operand and the local field)\r
+                        * instead of one, i.e:\r
+                        *\r
+                        *  SqlXmlExecutor.method(operand, field)\r
+                        *\r
+                        * instead of\r
+                        *\r
+                        *  <operand>.method(field).\r
+                        */\r
+                       if (xmlGen) {\r
+                               mb.callMethod(VMOpcode.INVOKEVIRTUAL, null,\r
+                                       methodName, resultTypeName, 2);\r
+                       }\r
+                       else {\r
+                               mb.callMethod(VMOpcode.INVOKEINTERFACE,\r
+                                       (String) null, methodName, resultTypeName, 1);\r
+                       }\r
+\r
+                       /*\r
+                       ** Store the result of the method call in the field, so we can re-use\r
+                       ** the object.\r
+                       */\r
+                       mb.putField(field);\r
+               } else {\r
+                       mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,\r
+                               methodName, resultTypeName, 0);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Determine the type the binary method is called on.\r
+        * By default, based on the receiver.\r
+        *\r
+        * Override in nodes that use methods on super-interfaces of\r
+        * the receiver's interface, such as comparisons.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public String getReceiverInterfaceName() throws StandardException {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(operand!=null,\r
+                                                               "cannot get interface without operand");\r
+               }\r
+\r
+               if (operatorType != -1)\r
+                       return receiverInterfaceType;\r
+               \r
+               return operand.getTypeCompiler().interfaceName();\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 expressions)\r
+        *              CONSTANT                        - immutable\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
+               /*\r
+               ** If we have nothing in the operator, then\r
+               ** it must be constant.\r
+               */\r
+               return (operand != null) ?\r
+                               operand.getOrderableVariantType() :\r
+                               Qualifier.CONSTANT;\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
+               Visitable returnNode = v.visit(this);\r
+\r
+               if (v.skipChildren(this))\r
+               {\r
+                       return returnNode;\r
+               }\r
+\r
+               if (operand != null && !v.stopTraversal())\r
+               {\r
+                       operand = (ValueNode)operand.accept(v);\r
+               }\r
+\r
+               return returnNode;\r
+       }\r
+\r
+    /**\r
+     * Add some additional arguments to our method call for\r
+     * XML related operations like XMLPARSE and XMLSERIALIZE.\r
+     * @param mb The MethodBuilder that will make the call.\r
+     * @return Number of parameters added.\r
+     */\r
+    protected int addXmlOpMethodParams(ExpressionClassBuilder acb,\r
+               MethodBuilder mb) throws StandardException\r
+    {\r
+        if ((operatorType != XMLPARSE_OP) && (operatorType != XMLSERIALIZE_OP))\r
+        // nothing to do.\r
+            return 0;\r
+\r
+        if (operatorType == XMLSERIALIZE_OP) {\r
+        // We push the target type's JDBC type id as well as\r
+        // the maximum width, since both are required when\r
+        // we actually perform the operation, and both are\r
+        // primitive types.  Note: we don't have to save\r
+        // any objects for XMLSERIALIZE because it doesn't\r
+        // require any XML-specific objects: it just returns\r
+        // the serialized version of the XML value, which we\r
+        // already found when the XML value was created (ex.\r
+        // as part of the XMLPARSE work).\r
+        // We also need to pass the collation type of the current\r
+        // compilation schema. If the JDBC type id is of type\r
+        // StringDataValue, then we should use the collation to\r
+        // decide whether we need to generate collation sensitive\r
+        // StringDataValue.\r
+            DataTypeDescriptor targetType =\r
+                (DataTypeDescriptor)additionalArgs[0];\r
+            mb.push(targetType.getJDBCTypeId());\r
+            mb.push(targetType.getMaximumWidth());\r
+            mb.push(getSchemaDescriptor(null, false).getCollationType());\r
+            return 3;\r
+        }\r
+\r
+        /* Else we're here for XMLPARSE. */\r
+\r
+        // Push activation, which we use at execution time to\r
+        // get our saved object (which will hold objects used\r
+        // for parsing/serializing) back.\r
+        acb.pushThisAsActivation(mb);\r
+\r
+        // Push our XML object (used for parsing/serializing) as\r
+        // a saved object, so that we can retrieve it at execution\r
+        // time.  This allows us to avoid having to re-create the\r
+        // objects for every row in a given result set.\r
+        mb.push(getCompilerContext().addSavedObject(sqlxUtil));\r
+\r
+        // Push whether or not we want to preserve whitespace.\r
+        mb.push(((Boolean)additionalArgs[0]).booleanValue());\r
+        return 3;\r
+    }\r
+    \r
+    /**\r
+     * @throws StandardException \r
+     * {@inheritDoc}\r
+     */\r
+    protected boolean isEquivalent(ValueNode o) throws StandardException\r
+    {\r
+       if (isSameNodeType(o)) \r
+       {\r
+               // the first condition in the || covers the case when \r
+               // both operands are null.\r
+               UnaryOperatorNode other = (UnaryOperatorNode)o;\r
+               return (operator.equals(other.operator) && \r
+                       ((operand == other.operand)|| \r
+                        ((operand != null) && operand.isEquivalent(other.operand))));\r
+       }\r
+       return false;\r
+    }\r
+}\r