--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.BinaryOperatorNode\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.sql.compile;\r
+\r
+import org.apache.derby.iapi.sql.compile.Visitable;\r
+import org.apache.derby.iapi.sql.compile.Visitor;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\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 java.lang.reflect.Modifier;\r
+import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;\r
+import org.apache.derby.impl.sql.compile.ActivationClassBuilder;\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 org.apache.derby.iapi.store.access.Qualifier;\r
+\r
+import org.apache.derby.iapi.reference.ClassName;\r
+import org.apache.derby.iapi.reference.SQLState;\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 BinaryOperatorNode represents a built-in binary operator as defined by\r
+ * the ANSI/ISO SQL standard. This covers operators like +, -, *, /, =, <, etc.\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 BinaryOperatorNode extends ValueNode\r
+{\r
+ String operator;\r
+ String methodName;\r
+ ValueNode receiver; // used in generation\r
+\r
+ /*\r
+ ** These identifiers are used in the grammar.\r
+ */\r
+ public final static int PLUS = 1;\r
+ public final static int MINUS = 2;\r
+ public final static int TIMES = 3;\r
+ public final static int DIVIDE = 4;\r
+ public final static int CONCATENATE = 5;\r
+ public final static int EQ = 6;\r
+ public final static int NE = 7;\r
+ public final static int GT = 8;\r
+ public final static int GE = 9;\r
+ public final static int LT = 10;\r
+ public final static int LE = 11;\r
+ public final static int AND = 12;\r
+ public final static int OR = 13;\r
+ public final static int LIKE = 14;\r
+\r
+ ValueNode leftOperand;\r
+ ValueNode rightOperand;\r
+\r
+ String leftInterfaceType;\r
+ String rightInterfaceType;\r
+ String resultInterfaceType;\r
+ int operatorType;\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 binary operators we just add the\r
+ // necessary code to _this_ class, similar to what is done in\r
+ // TernarnyOperatorNode. Subsequent binary operators (whether\r
+ // XML-related or not) should follow this example when\r
+ // possible.\r
+\r
+ public final static int XMLEXISTS_OP = 0;\r
+ public final static int XMLQUERY_OP = 1;\r
+\r
+ // NOTE: in the following 4 arrays, order\r
+ // IS important.\r
+\r
+ static final String[] BinaryOperators = {\r
+ "xmlexists",\r
+ "xmlquery"\r
+ };\r
+\r
+ static final String[] BinaryMethodNames = {\r
+ "XMLExists",\r
+ "XMLQuery"\r
+ };\r
+\r
+ static final String[] BinaryResultTypes = {\r
+ ClassName.BooleanDataValue, // XMLExists\r
+ ClassName.XMLDataValue // XMLQuery\r
+ };\r
+\r
+ static final String[][] BinaryArgTypes = {\r
+ {ClassName.StringDataValue, ClassName.XMLDataValue}, // XMLExists\r
+ {ClassName.StringDataValue, ClassName.XMLDataValue} // XMLQuery\r
+ };\r
+\r
+ // Class used to compile an XML query expression and/or load/process\r
+ // XML-specific objects.\r
+ private SqlXmlUtil sqlxUtil;\r
+\r
+ /**\r
+ * Initializer for a BinaryOperatorNode\r
+ *\r
+ * @param leftOperand The left operand of the node\r
+ * @param rightOperand The right operand of the node\r
+ * @param operator The name of the operator\r
+ * @param methodName The name of the method to call for this operator\r
+ * @param leftInterfaceType The name of the interface for the left operand\r
+ * @param rightInterfaceType The name of the interface for the right\r
+ * operand\r
+ */\r
+\r
+ public void init(\r
+ Object leftOperand,\r
+ Object rightOperand,\r
+ Object operator,\r
+ Object methodName,\r
+ Object leftInterfaceType,\r
+ Object rightInterfaceType)\r
+ {\r
+ this.leftOperand = (ValueNode) leftOperand;\r
+ this.rightOperand = (ValueNode) rightOperand;\r
+ this.operator = (String) operator;\r
+ this.methodName = (String) methodName;\r
+ this.leftInterfaceType = (String) leftInterfaceType;\r
+ this.rightInterfaceType = (String) rightInterfaceType;\r
+ this.operatorType = -1;\r
+ }\r
+\r
+ public void init(\r
+ Object leftOperand,\r
+ Object rightOperand,\r
+ Object leftInterfaceType,\r
+ Object rightInterfaceType)\r
+ {\r
+ this.leftOperand = (ValueNode) leftOperand;\r
+ this.rightOperand = (ValueNode) rightOperand;\r
+ this.leftInterfaceType = (String) leftInterfaceType;\r
+ this.rightInterfaceType = (String) rightInterfaceType;\r
+ this.operatorType = -1;\r
+ }\r
+\r
+ /**\r
+ * Initializer for a BinaryOperatorNode\r
+ *\r
+ * @param leftOperand The left operand of the node\r
+ * @param rightOperand The right operand of the node\r
+ * @param opType An Integer holding the operatorType\r
+ * for this operator.\r
+ */\r
+ public void init(\r
+ Object leftOperand,\r
+ Object rightOperand,\r
+ Object opType)\r
+ {\r
+ this.leftOperand = (ValueNode)leftOperand;\r
+ this.rightOperand = (ValueNode)rightOperand;\r
+ this.operatorType = ((Integer)opType).intValue();\r
+ this.operator = BinaryOperators[this.operatorType];\r
+ this.methodName = BinaryMethodNames[this.operatorType];\r
+ this.leftInterfaceType = BinaryArgTypes[this.operatorType][0];\r
+ this.rightInterfaceType = BinaryArgTypes[this.operatorType][1];\r
+ this.resultInterfaceType = BinaryResultTypes[this.operatorType];\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
+ * 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
+ * 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
+ * Set the interface type for the left and right arguments.\r
+ * Used when we don't know the interface type until\r
+ * later in binding.\r
+ */\r
+ public void setLeftRightInterfaceType(String iType)\r
+ {\r
+ leftInterfaceType = iType;\r
+ rightInterfaceType = iType;\r
+ this.operatorType = -1;\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 (leftOperand != null)\r
+ {\r
+ printLabel(depth, "leftOperand: ");\r
+ leftOperand.treePrint(depth + 1);\r
+ }\r
+\r
+ if (rightOperand != null)\r
+ {\r
+ printLabel(depth, "rightOperand: ");\r
+ rightOperand.treePrint(depth + 1);\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
+ *\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
+ leftOperand = leftOperand.bindExpression(fromList, subqueryList, \r
+ aggregateVector);\r
+ rightOperand = rightOperand.bindExpression(fromList, subqueryList, \r
+ aggregateVector);\r
+\r
+ if ((operatorType == XMLEXISTS_OP) || (operatorType == XMLQUERY_OP))\r
+ return bindXMLQuery();\r
+\r
+ /* Is there a ? parameter on the left? */\r
+ if (leftOperand.requiresTypeFromContext())\r
+ {\r
+ /*\r
+ ** It's an error if both operands are ? parameters.\r
+ */\r
+ if (rightOperand.requiresTypeFromContext())\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_BINARY_OPERANDS_BOTH_PARMS, \r
+ operator);\r
+ }\r
+\r
+ /* Set the left operand to the type of right parameter. */\r
+ leftOperand.setType(rightOperand.getTypeServices());\r
+ }\r
+\r
+ /* Is there a ? parameter on the right? */\r
+ if (rightOperand.requiresTypeFromContext())\r
+ {\r
+ /* Set the right operand to the type of the left parameter. */\r
+ rightOperand.setType(leftOperand.getTypeServices());\r
+ }\r
+\r
+ return genSQLJavaSQLTree();\r
+ }\r
+\r
+ /**\r
+ * Bind an XMLEXISTS or XMLQUERY operator. Makes sure\r
+ * the operand type and target type are both correct\r
+ * and sets the result type.\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public ValueNode bindXMLQuery()\r
+ throws StandardException\r
+ {\r
+ // Check operand types.\r
+ TypeId leftOperandType = leftOperand.getTypeId();\r
+ TypeId rightOperandType = rightOperand.getTypeId();\r
+\r
+ // Left operand is query expression and must be a string\r
+ // literal. SQL/XML spec doesn't allow params nor expressions\r
+ // 6.17: <XQuery expression> ::= <character string literal> \r
+ if (!(leftOperand instanceof CharConstantNode))\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_INVALID_XML_QUERY_EXPRESSION);\r
+ }\r
+ else {\r
+ // compile the query expression.\r
+ sqlxUtil = new SqlXmlUtil();\r
+ sqlxUtil.compileXQExpr(\r
+ ((CharConstantNode)leftOperand).getString(),\r
+ (operatorType == XMLEXISTS_OP ? "XMLEXISTS" : "XMLQUERY"));\r
+ }\r
+\r
+ // Right operand must be an XML data value. NOTE: This\r
+ // is a Derby-specific restriction, not an SQL/XML one.\r
+ // We have this restriction because the query engine\r
+ // that we use (currently Xalan) cannot handle non-XML\r
+ // context items.\r
+ if ((rightOperandType != null) &&\r
+ !rightOperandType.isXMLTypeId())\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_INVALID_CONTEXT_ITEM_TYPE,\r
+ rightOperandType.getSQLTypeName());\r
+ }\r
+\r
+ // Is there a ? parameter on the right?\r
+ if (rightOperand.requiresTypeFromContext())\r
+ {\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
+\r
+ // Set the result type of this operator.\r
+ if (operatorType == XMLEXISTS_OP) {\r
+ // For XMLEXISTS, the result type is always SQLBoolean.\r
+ // The "true" in the next line says that the result\r
+ // can be nullable--which it can be if evaluation of\r
+ // the expression returns a null (this is per SQL/XML\r
+ // spec, 8.4)\r
+ setType(new DataTypeDescriptor(TypeId.BOOLEAN_ID, true));\r
+ }\r
+ else {\r
+ // The result of an XMLQUERY operator is always another\r
+ // XML data value, per SQL/XML spec 6.17: "...yielding a value\r
+ // X1 of an XML type."\r
+ setType(DataTypeDescriptor.getBuiltInDataTypeDescriptor(\r
+ StoredFormatIds.XML_TYPE_ID));\r
+ }\r
+\r
+ return genSQLJavaSQLTree();\r
+ }\r
+\r
+ /** generate a SQL->Java->SQL conversion tree above the left and right\r
+ * operand of this Binary Operator Node if needed. Subclasses can override\r
+ * the default behavior.\r
+ */\r
+ public ValueNode genSQLJavaSQLTree() throws StandardException\r
+ {\r
+ TypeId leftTypeId = leftOperand.getTypeId();\r
+ \r
+ if (leftTypeId.userType())\r
+ leftOperand = leftOperand.genSQLJavaSQLTree();\r
+\r
+ TypeId rightTypeId = rightOperand.getTypeId();\r
+ if (rightTypeId.userType())\r
+ rightOperand = rightOperand.genSQLJavaSQLTree();\r
+\r
+ return this;\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
+ leftOperand = leftOperand.preprocess(numTables,\r
+ outerFromList, outerSubqueryList,\r
+ outerPredicateList);\r
+ rightOperand = rightOperand.preprocess(numTables,\r
+ outerFromList, outerSubqueryList,\r
+ outerPredicateList);\r
+ return this;\r
+ }\r
+\r
+ /**\r
+ * Do code generation for this binary operator.\r
+ *\r
+ * @param acb The ExpressionClassBuilder for the class we're generating\r
+ * @param mb The method the code to place the code\r
+ *\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public void generateExpression(ExpressionClassBuilder acb,\r
+ MethodBuilder mb)\r
+ throws StandardException\r
+ {\r
+ /* If this BinaryOperatorNode was created as a part of an IN-list\r
+ * "probe predicate" then we do not want to generate the relational\r
+ * operator itself; instead we want to generate the underlying\r
+ * IN-list for which this operator node was created.\r
+ *\r
+ * We'll get here in situations where the optimizer chooses a plan\r
+ * for which the probe predicate is *not* a useful start/stop key\r
+ * and thus is not being used for execution-time index probing.\r
+ * In this case we are effectively "reverting" the probe predicate\r
+ * back to the InListOperatorNode from which it was created. Or put\r
+ * another way, we are "giving up" on index multi-probing and simply\r
+ * generating the original IN-list as a regular restriction.\r
+ */\r
+ if (this instanceof BinaryRelationalOperatorNode)\r
+ {\r
+ InListOperatorNode ilon =\r
+ ((BinaryRelationalOperatorNode)this).getInListOp();\r
+\r
+ if (ilon != null)\r
+ {\r
+ ilon.generateExpression(acb, mb);\r
+ return;\r
+ }\r
+ }\r
+\r
+ String resultTypeName;\r
+ String receiverType;\r
+\r
+/*\r
+** if i have a operator.getOrderableType() == constant, then just cache \r
+** it in a field. if i have QUERY_INVARIANT, then it would be good to\r
+** cache it in something that is initialized each execution,\r
+** but how?\r
+*/\r
+\r
+ // If we're dealing with XMLEXISTS or XMLQUERY, there is some\r
+ // additional work to be done.\r
+ boolean xmlGen =\r
+ (operatorType == XMLQUERY_OP) || (operatorType == XMLEXISTS_OP);\r
+\r
+ if (xmlGen) {\r
+ // We create an execution-time object so that we can retrieve\r
+ // saved objects (esp. our compiled query expression) from\r
+ // the activation. We do this for two reasons: 1) this level\r
+ // of indirection allows us to separate the XML data type\r
+ // from the required XML implementation classes (esp. JAXP\r
+ // and Xalan classes)--for more on how this works, see the\r
+ // comments in SqlXmlUtil.java; and 2) we can take\r
+ // the XML query expression, which we've already compiled,\r
+ // and pass it to the execution-time object for each row,\r
+ // which means that we only have to compile the query\r
+ // expression once per SQL statement (instead of once per\r
+ // row); see SqlXmlExecutor.java for more.\r
+ mb.pushNewStart(\r
+ "org.apache.derby.impl.sql.execute.SqlXmlExecutor");\r
+ mb.pushNewComplete(addXmlOpMethodParams(acb, mb));\r
+ }\r
+\r
+ /*\r
+ ** The receiver is the operand with the higher type precedence.\r
+ ** Like always makes the left the receiver.\r
+ **\r
+ */\r
+ if (leftOperand.getTypeId().typePrecedence() >\r
+ rightOperand.getTypeId().typePrecedence())\r
+ {\r
+ receiver = leftOperand;\r
+ /*\r
+ ** let the receiver type be determined by an\r
+ ** overridable method so that if methods are\r
+ ** not implemented on the lowest interface of\r
+ ** a class, they can note that in the implementation\r
+ ** of the node that uses the method.\r
+ */\r
+ receiverType = (operatorType == -1)\r
+ ? getReceiverInterfaceName()\r
+ : leftInterfaceType;\r
+\r
+ /*\r
+ ** Generate (with <left expression> only being evaluated once)\r
+ **\r
+ ** <left expression>.method(<left expression>, <right expression>...)\r
+ */\r
+\r
+ leftOperand.generateExpression(acb, mb);\r
+ mb.cast(receiverType); // cast the method instance\r
+ // stack: left\r
+ \r
+ mb.dup();\r
+ mb.cast(leftInterfaceType);\r
+ // stack: left, left\r
+ \r
+ rightOperand.generateExpression(acb, mb);\r
+ mb.cast(rightInterfaceType); // second arg with cast\r
+ // stack: left, left, right\r
+ }\r
+ else\r
+ {\r
+ receiver = rightOperand;\r
+ /*\r
+ ** let the receiver type be determined by an\r
+ ** overridable method so that if methods are\r
+ ** not implemented on the lowest interface of\r
+ ** a class, they can note that in the implementation\r
+ ** of the node that uses the method.\r
+ */\r
+ receiverType = (operatorType == -1)\r
+ ? getReceiverInterfaceName()\r
+ : rightInterfaceType;\r
+\r
+ /*\r
+ ** Generate (with <right expression> only being evaluated once)\r
+ **\r
+ ** <right expression>.method(<left expression>, <right expression>)\r
+ **\r
+ ** UNLESS we're generating an XML operator such as XMLEXISTS.\r
+ ** In that case we want to generate\r
+ ** \r
+ ** SqlXmlExecutor.method(left, right)"\r
+ **\r
+ ** and we've already pushed the SqlXmlExecutor object to\r
+ ** the stack.\r
+ */\r
+\r
+ rightOperand.generateExpression(acb, mb); \r
+ mb.cast(receiverType); // cast the method instance\r
+ // stack: right\r
+ \r
+ if (!xmlGen) {\r
+ mb.dup();\r
+ mb.cast(rightInterfaceType);\r
+ // stack: right,right\r
+ }\r
+ \r
+ leftOperand.generateExpression(acb, mb);\r
+ mb.cast(leftInterfaceType); // second arg with cast\r
+ // stack: right,right,left\r
+ \r
+ mb.swap();\r
+ // stack: right,left,right \r
+ }\r
+\r
+ /* Figure out the result type name */\r
+ resultTypeName = (operatorType == -1)\r
+ ? getTypeCompiler().interfaceName()\r
+ : resultInterfaceType;\r
+\r
+ // Boolean return types don't need a result field\r
+ boolean needField = !getTypeId().isBooleanTypeId();\r
+\r
+ if (needField) {\r
+\r
+ /* Allocate an object for re-use to hold the result of the operator */\r
+ LocalField resultField =\r
+ acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);\r
+\r
+ /*\r
+ ** Call the method for this operator.\r
+ */\r
+ mb.getField(resultField); // third arg\r
+ //following method is special code for concatenation where if field is null, we want it to be initialized to NULL SQLxxx type object\r
+ //before generating code "field = method(p1, p2, field);"\r
+ initializeResultField(acb, mb, resultField);\r
+\r
+ /* pass statically calculated scale to decimal divide method to make\r
+ * result set scale consistent, beetle 3901\r
+ */\r
+ int jdbcType;\r
+ if ((getTypeServices() != null) &&\r
+ ((jdbcType = getTypeServices().getJDBCTypeId()) == java.sql.Types.DECIMAL ||\r
+ jdbcType == java.sql.Types.NUMERIC) &&\r
+ operator.equals("/"))\r
+ {\r
+ mb.push(getTypeServices().getScale()); // 4th arg\r
+ mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, 4);\r
+ }\r
+ else if (xmlGen) {\r
+ // This is for an XMLQUERY operation, so invoke the method\r
+ // on our execution-time object.\r
+ mb.callMethod(VMOpcode.INVOKEVIRTUAL, null,\r
+ methodName, resultTypeName, 3);\r
+ }\r
+ else\r
+ mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, 3);\r
+\r
+ //the need for following if was realized while fixing bug 5704 where decimal*decimal was resulting an overflow value but we were not detecting it\r
+ if (getTypeId().variableLength())//since result type is numeric variable length, generate setWidth code.\r
+ {\r
+ if (getTypeId().isNumericTypeId())\r
+ {\r
+ // to leave the DataValueDescriptor value on the stack, since setWidth is void\r
+ mb.dup();\r
+\r
+ mb.push(getTypeServices().getPrecision());\r
+ mb.push(getTypeServices().getScale());\r
+ mb.push(true);\r
+ mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue, "setWidth", "void", 3);\r
+ }\r
+ }\r
+\r
+\r
+ /*\r
+ ** Store the result of the method call in the field, so we can re-use\r
+ ** the object.\r
+ */\r
+\r
+ mb.putField(resultField);\r
+ } else {\r
+ if (xmlGen) {\r
+ // This is for an XMLEXISTS operation, so invoke the method\r
+ // on our execution-time object.\r
+ mb.callMethod(VMOpcode.INVOKEVIRTUAL, null,\r
+ methodName, resultTypeName, 2);\r
+ }\r
+ else {\r
+ mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType,\r
+ methodName, resultTypeName, 2);\r
+ }\r
+ }\r
+ }\r
+\r
+ //following method is no-op here but in concatenation node, this method is used to check if resultField is null,\r
+ //and if yes, then we want it to be initialized to NULL SQLxxx type object\r
+ protected void initializeResultField(ExpressionClassBuilder acb, MethodBuilder mb, LocalField resultField)\r
+ throws StandardException\r
+ {\r
+ }\r
+\r
+ /**\r
+ * Set the leftOperand to the specified ValueNode\r
+ *\r
+ * @param newLeftOperand The new leftOperand\r
+ */\r
+ public void setLeftOperand(ValueNode newLeftOperand)\r
+ {\r
+ leftOperand = newLeftOperand;\r
+ }\r
+\r
+ /**\r
+ * Get the leftOperand\r
+ *\r
+ * @return The current leftOperand.\r
+ */\r
+ public ValueNode getLeftOperand()\r
+ {\r
+ return leftOperand;\r
+ }\r
+\r
+ /**\r
+ * Set the rightOperand to the specified ValueNode\r
+ *\r
+ * @param newRightOperand The new rightOperand\r
+ */\r
+ public void setRightOperand(ValueNode newRightOperand)\r
+ {\r
+ rightOperand = newRightOperand;\r
+ }\r
+\r
+ /**\r
+ * Get the rightOperand\r
+ *\r
+ * @return The current rightOperand.\r
+ */\r
+ public ValueNode getRightOperand()\r
+ {\r
+ return rightOperand;\r
+ }\r
+\r
+ /**\r
+ * Categorize this predicate. Initially, this means\r
+ * building a bit map of the referenced tables for each predicate.\r
+ * If the source of this ColumnReference (at the next underlying level) \r
+ * is not a ColumnReference or a VirtualColumnNode then this predicate\r
+ * will not be pushed down.\r
+ *\r
+ * For example, in:\r
+ * select * from (select 1 from s) a (x) where x = 1\r
+ * we will not push down x = 1.\r
+ * NOTE: It would be easy to handle the case of a constant, but if the\r
+ * inner SELECT returns an arbitrary expression, then we would have to copy\r
+ * that tree into the pushed predicate, and that tree could contain\r
+ * subqueries and method calls.\r
+ * RESOLVE - revisit this issue once we have views.\r
+ *\r
+ * @param referencedTabs JBitSet with bit map of referenced FromTables\r
+ * @param simplePredsOnly Whether or not to consider method\r
+ * calls, field references and conditional nodes\r
+ * when building bit map\r
+ *\r
+ * @return boolean Whether or not source.expression is a ColumnReference\r
+ * or a VirtualColumnNode.\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)\r
+ throws StandardException\r
+ {\r
+ boolean pushable;\r
+ pushable = leftOperand.categorize(referencedTabs, simplePredsOnly);\r
+ pushable = (rightOperand.categorize(referencedTabs, simplePredsOnly) && pushable);\r
+ return pushable;\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
+ leftOperand = leftOperand.remapColumnReferencesToExpressions();\r
+ rightOperand = rightOperand.remapColumnReferencesToExpressions();\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 (leftOperand.isConstantExpression() &&\r
+ rightOperand.isConstantExpression());\r
+ }\r
+\r
+ /** @see ValueNode#constantExpression */\r
+ public boolean constantExpression(PredicateList whereClause)\r
+ {\r
+ return (leftOperand.constantExpression(whereClause) &&\r
+ rightOperand.constantExpression(whereClause));\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(receiver!=null,"can't get receiver interface name until receiver is set");\r
+ }\r
+\r
+ return receiver.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 - 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
+ int leftType = leftOperand.getOrderableVariantType();\r
+ int rightType = rightOperand.getOrderableVariantType();\r
+\r
+ return Math.min(leftType, rightType);\r
+ }\r
+\r
+ /**\r
+ * Swap the left and right sides.\r
+ */\r
+ void swapOperands()\r
+ {\r
+ String tmpInterfaceType = leftInterfaceType;\r
+ ValueNode tmpVN = leftOperand;\r
+\r
+ leftOperand = rightOperand;\r
+ rightOperand = tmpVN;\r
+ leftInterfaceType = rightInterfaceType;\r
+ rightInterfaceType = tmpInterfaceType;\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 (leftOperand != null && !v.stopTraversal())\r
+ {\r
+ leftOperand = (ValueNode)leftOperand.accept(v);\r
+ }\r
+\r
+ if (rightOperand != null && !v.stopTraversal())\r
+ {\r
+ rightOperand = (ValueNode)rightOperand.accept(v);\r
+ }\r
+ \r
+ return returnNode;\r
+ }\r
+\r
+ /**\r
+ * @inheritDoc\r
+ */\r
+ protected boolean isEquivalent(ValueNode o) throws StandardException\r
+ {\r
+ if (!isSameNodeType(o))\r
+ {\r
+ return false;\r
+ }\r
+ BinaryOperatorNode other = (BinaryOperatorNode)o;\r
+ return methodName.equals(other.methodName)\r
+ && leftOperand.isEquivalent(other.leftOperand)\r
+ && rightOperand.isEquivalent(other.rightOperand);\r
+ }\r
+\r
+ /**\r
+ * Push the fields necessary to generate an instance of\r
+ * SqlXmlExecutor, which will then be used at execution\r
+ * time to retrieve the compiled XML query expression,\r
+ * along with any other XML-specific objects.\r
+ *\r
+ * @param acb The ExpressionClassBuilder for the class we're generating\r
+ * @param mb The method the code to place the code\r
+ *\r
+ * @return The number of items that this method pushed onto\r
+ * the mb's stack.\r
+ */\r
+ private int addXmlOpMethodParams(ExpressionClassBuilder acb,\r
+ MethodBuilder mb) throws StandardException\r
+ {\r
+ // Push activation so that we can get our saved object\r
+ // (which will hold the compiled XML query expression)\r
+ // back at execute time.\r
+ acb.pushThisAsActivation(mb);\r
+\r
+ // Push our saved object (the compiled query and XML-specific\r
+ // objects).\r
+ mb.push(getCompilerContext().addSavedObject(sqlxUtil));\r
+\r
+ // We pushed 2 items to the stack.\r
+ return 2;\r
+ }\r
+}\r