001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.BinaryOperatorNode
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.sql.compile.Visitable;
025: import org.apache.derby.iapi.sql.compile.Visitor;
026: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
027: import org.apache.derby.iapi.error.StandardException;
028:
029: import org.apache.derby.iapi.services.sanity.SanityManager;
030: import org.apache.derby.iapi.services.compiler.MethodBuilder;
031: import org.apache.derby.iapi.services.compiler.LocalField;
032: import org.apache.derby.iapi.services.io.StoredFormatIds;
033:
034: import java.lang.reflect.Modifier;
035: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
036: import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
037: import org.apache.derby.iapi.types.StringDataValue;
038: import org.apache.derby.iapi.types.TypeId;
039: import org.apache.derby.iapi.types.DataTypeDescriptor;
040: import org.apache.derby.iapi.types.SqlXmlUtil;
041:
042: import org.apache.derby.iapi.store.access.Qualifier;
043:
044: import org.apache.derby.iapi.reference.ClassName;
045: import org.apache.derby.iapi.reference.SQLState;
046:
047: import org.apache.derby.iapi.util.JBitSet;
048: import org.apache.derby.iapi.services.classfile.VMOpcode;
049:
050: import java.sql.Types;
051: import java.util.Vector;
052:
053: /**
054: * A BinaryOperatorNode represents a built-in binary operator as defined by
055: * the ANSI/ISO SQL standard. This covers operators like +, -, *, /, =, <, etc.
056: * Java operators are not represented here: the JSQL language allows Java
057: * methods to be called from expressions, but not Java operators.
058: *
059: * @author Jeff Lichtman
060: */
061:
062: public class BinaryOperatorNode extends ValueNode {
063: String operator;
064: String methodName;
065: ValueNode receiver; // used in generation
066:
067: /*
068: ** These identifiers are used in the grammar.
069: */
070: public final static int PLUS = 1;
071: public final static int MINUS = 2;
072: public final static int TIMES = 3;
073: public final static int DIVIDE = 4;
074: public final static int CONCATENATE = 5;
075: public final static int EQ = 6;
076: public final static int NE = 7;
077: public final static int GT = 8;
078: public final static int GE = 9;
079: public final static int LT = 10;
080: public final static int LE = 11;
081: public final static int AND = 12;
082: public final static int OR = 13;
083: public final static int LIKE = 14;
084:
085: ValueNode leftOperand;
086: ValueNode rightOperand;
087:
088: String leftInterfaceType;
089: String rightInterfaceType;
090: String resultInterfaceType;
091: int operatorType;
092:
093: // At the time of adding XML support, it was decided that
094: // we should avoid creating new OperatorNodes where possible.
095: // So for the XML-related binary operators we just add the
096: // necessary code to _this_ class, similar to what is done in
097: // TernarnyOperatorNode. Subsequent binary operators (whether
098: // XML-related or not) should follow this example when
099: // possible.
100:
101: public final static int XMLEXISTS_OP = 0;
102: public final static int XMLQUERY_OP = 1;
103:
104: // NOTE: in the following 4 arrays, order
105: // IS important.
106:
107: static final String[] BinaryOperators = { "xmlexists", "xmlquery" };
108:
109: static final String[] BinaryMethodNames = { "XMLExists", "XMLQuery" };
110:
111: static final String[] BinaryResultTypes = {
112: ClassName.BooleanDataValue, // XMLExists
113: ClassName.XMLDataValue // XMLQuery
114: };
115:
116: static final String[][] BinaryArgTypes = {
117: { ClassName.StringDataValue, ClassName.XMLDataValue }, // XMLExists
118: { ClassName.StringDataValue, ClassName.XMLDataValue } // XMLQuery
119: };
120:
121: // Class used to compile an XML query expression and/or load/process
122: // XML-specific objects.
123: private SqlXmlUtil sqlxUtil;
124:
125: /**
126: * Initializer for a BinaryOperatorNode
127: *
128: * @param leftOperand The left operand of the node
129: * @param rightOperand The right operand of the node
130: * @param operator The name of the operator
131: * @param methodName The name of the method to call for this operator
132: * @param leftInterfaceType The name of the interface for the left operand
133: * @param rightInterfaceType The name of the interface for the right
134: * operand
135: */
136:
137: public void init(Object leftOperand, Object rightOperand,
138: Object operator, Object methodName,
139: Object leftInterfaceType, Object rightInterfaceType) {
140: this .leftOperand = (ValueNode) leftOperand;
141: this .rightOperand = (ValueNode) rightOperand;
142: this .operator = (String) operator;
143: this .methodName = (String) methodName;
144: this .leftInterfaceType = (String) leftInterfaceType;
145: this .rightInterfaceType = (String) rightInterfaceType;
146: this .operatorType = -1;
147: }
148:
149: public void init(Object leftOperand, Object rightOperand,
150: Object leftInterfaceType, Object rightInterfaceType) {
151: this .leftOperand = (ValueNode) leftOperand;
152: this .rightOperand = (ValueNode) rightOperand;
153: this .leftInterfaceType = (String) leftInterfaceType;
154: this .rightInterfaceType = (String) rightInterfaceType;
155: this .operatorType = -1;
156: }
157:
158: /**
159: * Initializer for a BinaryOperatorNode
160: *
161: * @param leftOperand The left operand of the node
162: * @param rightOperand The right operand of the node
163: * @param opType An Integer holding the operatorType
164: * for this operator.
165: */
166: public void init(Object leftOperand, Object rightOperand,
167: Object opType) {
168: this .leftOperand = (ValueNode) leftOperand;
169: this .rightOperand = (ValueNode) rightOperand;
170: this .operatorType = ((Integer) opType).intValue();
171: this .operator = BinaryOperators[this .operatorType];
172: this .methodName = BinaryMethodNames[this .operatorType];
173: this .leftInterfaceType = BinaryArgTypes[this .operatorType][0];
174: this .rightInterfaceType = BinaryArgTypes[this .operatorType][1];
175: this .resultInterfaceType = BinaryResultTypes[this .operatorType];
176: }
177:
178: /**
179: * Convert this object to a String. See comments in QueryTreeNode.java
180: * for how this should be done for tree printing.
181: *
182: * @return This object as a String
183: */
184:
185: public String toString() {
186: if (SanityManager.DEBUG) {
187: return "operator: " + operator + "\n" + "methodName: "
188: + methodName + "\n" + super .toString();
189: } else {
190: return "";
191: }
192: }
193:
194: /**
195: * Set the operator.
196: *
197: * @param operator The operator.
198: */
199: void setOperator(String operator) {
200: this .operator = operator;
201: this .operatorType = -1;
202: }
203:
204: /**
205: * Set the methodName.
206: *
207: * @param methodName The methodName.
208: */
209: void setMethodName(String methodName) {
210: this .methodName = methodName;
211: this .operatorType = -1;
212: }
213:
214: /**
215: * Set the interface type for the left and right arguments.
216: * Used when we don't know the interface type until
217: * later in binding.
218: */
219: public void setLeftRightInterfaceType(String iType) {
220: leftInterfaceType = iType;
221: rightInterfaceType = iType;
222: this .operatorType = -1;
223: }
224:
225: /**
226: * Set the clause that this node appears in.
227: *
228: * @param clause The clause that this node appears in.
229: */
230: public void setClause(int clause) {
231: super .setClause(clause);
232: leftOperand.setClause(clause);
233: rightOperand.setClause(clause);
234: }
235:
236: /**
237: * Prints the sub-nodes of this object. See QueryTreeNode.java for
238: * how tree printing is supposed to work.
239: *
240: * @param depth The depth of this node in the tree
241: */
242:
243: public void printSubNodes(int depth) {
244: if (SanityManager.DEBUG) {
245: super .printSubNodes(depth);
246:
247: if (leftOperand != null) {
248: printLabel(depth, "leftOperand: ");
249: leftOperand.treePrint(depth + 1);
250: }
251:
252: if (rightOperand != null) {
253: printLabel(depth, "rightOperand: ");
254: rightOperand.treePrint(depth + 1);
255: }
256: }
257: }
258:
259: /**
260: * Bind this expression. This means binding the sub-expressions,
261: * as well as figuring out what the return type is for this expression.
262: *
263: * @param fromList The FROM list for the query this
264: * expression is in, for binding columns.
265: * @param subqueryList The subquery list being built as we find SubqueryNodes
266: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
267: *
268: * @return The new top of the expression tree.
269: *
270: * @exception StandardException Thrown on error
271: */
272:
273: public ValueNode bindExpression(FromList fromList,
274: SubqueryList subqueryList, Vector aggregateVector)
275: throws StandardException {
276: leftOperand = leftOperand.bindExpression(fromList,
277: subqueryList, aggregateVector);
278: rightOperand = rightOperand.bindExpression(fromList,
279: subqueryList, aggregateVector);
280:
281: if ((operatorType == XMLEXISTS_OP)
282: || (operatorType == XMLQUERY_OP))
283: return bindXMLQuery();
284:
285: /* Is there a ? parameter on the left? */
286: if (leftOperand.requiresTypeFromContext()) {
287: /*
288: ** It's an error if both operands are ? parameters.
289: */
290: if (rightOperand.requiresTypeFromContext()) {
291: throw StandardException.newException(
292: SQLState.LANG_BINARY_OPERANDS_BOTH_PARMS,
293: operator);
294: }
295:
296: /* Set the left operand to the type of right parameter. */
297: leftOperand.setType(rightOperand.getTypeServices());
298: }
299:
300: /* Is there a ? parameter on the right? */
301: if (rightOperand.requiresTypeFromContext()) {
302: /* Set the right operand to the type of the left parameter. */
303: rightOperand.setType(leftOperand.getTypeServices());
304: }
305:
306: return genSQLJavaSQLTree();
307: }
308:
309: /**
310: * Bind an XMLEXISTS or XMLQUERY operator. Makes sure
311: * the operand type and target type are both correct
312: * and sets the result type.
313: *
314: * @exception StandardException Thrown on error
315: */
316: public ValueNode bindXMLQuery() throws StandardException {
317: // Check operand types.
318: TypeId leftOperandType = leftOperand.getTypeId();
319: TypeId rightOperandType = rightOperand.getTypeId();
320:
321: // Left operand is query expression and must be a string
322: // literal. SQL/XML spec doesn't allow params nor expressions
323: // 6.17: <XQuery expression> ::= <character string literal>
324: if (!(leftOperand instanceof CharConstantNode)) {
325: throw StandardException
326: .newException(SQLState.LANG_INVALID_XML_QUERY_EXPRESSION);
327: } else {
328: // compile the query expression.
329: sqlxUtil = new SqlXmlUtil();
330: sqlxUtil.compileXQExpr(((CharConstantNode) leftOperand)
331: .getString(),
332: (operatorType == XMLEXISTS_OP ? "XMLEXISTS"
333: : "XMLQUERY"));
334: }
335:
336: // Right operand must be an XML data value. NOTE: This
337: // is a Derby-specific restriction, not an SQL/XML one.
338: // We have this restriction because the query engine
339: // that we use (currently Xalan) cannot handle non-XML
340: // context items.
341: if ((rightOperandType != null)
342: && !rightOperandType.isXMLTypeId()) {
343: throw StandardException.newException(
344: SQLState.LANG_INVALID_CONTEXT_ITEM_TYPE,
345: rightOperandType.getSQLTypeName());
346: }
347:
348: // Is there a ? parameter on the right?
349: if (rightOperand.requiresTypeFromContext()) {
350: // For now, since JDBC has no type defined for XML, we
351: // don't allow binding to an XML parameter.
352: throw StandardException
353: .newException(SQLState.LANG_ATTEMPT_TO_BIND_XML);
354: }
355:
356: // Set the result type of this operator.
357: if (operatorType == XMLEXISTS_OP) {
358: // For XMLEXISTS, the result type is always SQLBoolean.
359: // The "true" in the next line says that the result
360: // can be nullable--which it can be if evaluation of
361: // the expression returns a null (this is per SQL/XML
362: // spec, 8.4)
363: setType(new DataTypeDescriptor(TypeId.BOOLEAN_ID, true));
364: } else {
365: // The result of an XMLQUERY operator is always another
366: // XML data value, per SQL/XML spec 6.17: "...yielding a value
367: // X1 of an XML type."
368: setType(DataTypeDescriptor
369: .getBuiltInDataTypeDescriptor(StoredFormatIds.XML_TYPE_ID));
370: }
371:
372: return genSQLJavaSQLTree();
373: }
374:
375: /** generate a SQL->Java->SQL conversion tree above the left and right
376: * operand of this Binary Operator Node if needed. Subclasses can override
377: * the default behavior.
378: */
379: public ValueNode genSQLJavaSQLTree() throws StandardException {
380: TypeId leftTypeId = leftOperand.getTypeId();
381:
382: if (leftTypeId.userType())
383: leftOperand = leftOperand.genSQLJavaSQLTree();
384:
385: TypeId rightTypeId = rightOperand.getTypeId();
386: if (rightTypeId.userType())
387: rightOperand = rightOperand.genSQLJavaSQLTree();
388:
389: return this ;
390: }
391:
392: /**
393: * Preprocess an expression tree. We do a number of transformations
394: * here (including subqueries, IN lists, LIKE and BETWEEN) plus
395: * subquery flattening.
396: * NOTE: This is done before the outer ResultSetNode is preprocessed.
397: *
398: * @param numTables Number of tables in the DML Statement
399: * @param outerFromList FromList from outer query block
400: * @param outerSubqueryList SubqueryList from outer query block
401: * @param outerPredicateList PredicateList from outer query block
402: *
403: * @return The modified expression
404: *
405: * @exception StandardException Thrown on error
406: */
407: public ValueNode preprocess(int numTables, FromList outerFromList,
408: SubqueryList outerSubqueryList,
409: PredicateList outerPredicateList) throws StandardException {
410: leftOperand = leftOperand.preprocess(numTables, outerFromList,
411: outerSubqueryList, outerPredicateList);
412: rightOperand = rightOperand.preprocess(numTables,
413: outerFromList, outerSubqueryList, outerPredicateList);
414: return this ;
415: }
416:
417: /**
418: * Do code generation for this binary operator.
419: *
420: * @param acb The ExpressionClassBuilder for the class we're generating
421: * @param mb The method the code to place the code
422: *
423: *
424: * @exception StandardException Thrown on error
425: */
426:
427: public void generateExpression(ExpressionClassBuilder acb,
428: MethodBuilder mb) throws StandardException {
429: String resultTypeName;
430: String receiverType;
431:
432: /*
433: ** if i have a operator.getOrderableType() == constant, then just cache
434: ** it in a field. if i have QUERY_INVARIANT, then it would be good to
435: ** cache it in something that is initialized each execution,
436: ** but how?
437: */
438:
439: // If we're dealing with XMLEXISTS or XMLQUERY, there is some
440: // additional work to be done.
441: boolean xmlGen = (operatorType == XMLQUERY_OP)
442: || (operatorType == XMLEXISTS_OP);
443:
444: if (xmlGen) {
445: // We create an execution-time object so that we can retrieve
446: // saved objects (esp. our compiled query expression) from
447: // the activation. We do this for two reasons: 1) this level
448: // of indirection allows us to separate the XML data type
449: // from the required XML implementation classes (esp. JAXP
450: // and Xalan classes)--for more on how this works, see the
451: // comments in SqlXmlUtil.java; and 2) we can take
452: // the XML query expression, which we've already compiled,
453: // and pass it to the execution-time object for each row,
454: // which means that we only have to compile the query
455: // expression once per SQL statement (instead of once per
456: // row); see SqlXmlExecutor.java for more.
457: mb
458: .pushNewStart("org.apache.derby.impl.sql.execute.SqlXmlExecutor");
459: mb.pushNewComplete(addXmlOpMethodParams(acb, mb));
460: }
461:
462: /*
463: ** The receiver is the operand with the higher type precedence.
464: ** Like always makes the left the receiver.
465: **
466: */
467: if (leftOperand.getTypeId().typePrecedence() > rightOperand
468: .getTypeId().typePrecedence()) {
469: receiver = leftOperand;
470: /*
471: ** let the receiver type be determined by an
472: ** overridable method so that if methods are
473: ** not implemented on the lowest interface of
474: ** a class, they can note that in the implementation
475: ** of the node that uses the method.
476: */
477: receiverType = (operatorType == -1) ? getReceiverInterfaceName()
478: : leftInterfaceType;
479:
480: /*
481: ** Generate (with <left expression> only being evaluated once)
482: **
483: ** <left expression>.method(<left expression>, <right expression>...)
484: */
485:
486: leftOperand.generateExpression(acb, mb);
487: mb.cast(receiverType); // cast the method instance
488: // stack: left
489:
490: mb.dup();
491: mb.cast(leftInterfaceType);
492: // stack: left, left
493:
494: rightOperand.generateExpression(acb, mb);
495: mb.cast(rightInterfaceType); // second arg with cast
496: // stack: left, left, right
497: } else {
498: receiver = rightOperand;
499: /*
500: ** let the receiver type be determined by an
501: ** overridable method so that if methods are
502: ** not implemented on the lowest interface of
503: ** a class, they can note that in the implementation
504: ** of the node that uses the method.
505: */
506: receiverType = (operatorType == -1) ? getReceiverInterfaceName()
507: : rightInterfaceType;
508:
509: /*
510: ** Generate (with <right expression> only being evaluated once)
511: **
512: ** <right expression>.method(<left expression>, <right expression>)
513: **
514: ** UNLESS we're generating an XML operator such as XMLEXISTS.
515: ** In that case we want to generate
516: **
517: ** SqlXmlExecutor.method(left, right)"
518: **
519: ** and we've already pushed the SqlXmlExecutor object to
520: ** the stack.
521: */
522:
523: rightOperand.generateExpression(acb, mb);
524: mb.cast(receiverType); // cast the method instance
525: // stack: right
526:
527: if (!xmlGen) {
528: mb.dup();
529: mb.cast(rightInterfaceType);
530: // stack: right,right
531: }
532:
533: leftOperand.generateExpression(acb, mb);
534: mb.cast(leftInterfaceType); // second arg with cast
535: // stack: right,right,left
536:
537: mb.swap();
538: // stack: right,left,right
539: }
540:
541: /* Figure out the result type name */
542: resultTypeName = (operatorType == -1) ? getTypeCompiler()
543: .interfaceName() : resultInterfaceType;
544:
545: // Boolean return types don't need a result field
546: boolean needField = !getTypeId().isBooleanTypeId();
547:
548: if (needField) {
549:
550: /* Allocate an object for re-use to hold the result of the operator */
551: LocalField resultField = acb.newFieldDeclaration(
552: Modifier.PRIVATE, resultTypeName);
553:
554: /*
555: ** Call the method for this operator.
556: */
557: mb.getField(resultField); // third arg
558: //following method is special code for concatenation where if field is null, we want it to be initialized to NULL SQLxxx type object
559: //before generating code "field = method(p1, p2, field);"
560: initializeResultField(acb, mb, resultField);
561:
562: /* pass statically calculated scale to decimal divide method to make
563: * result set scale consistent, beetle 3901
564: */
565: int jdbcType;
566: if ((dataTypeServices != null)
567: && ((jdbcType = dataTypeServices.getJDBCTypeId()) == java.sql.Types.DECIMAL || jdbcType == java.sql.Types.NUMERIC)
568: && operator.equals("/")) {
569: mb.push(dataTypeServices.getScale()); // 4th arg
570: mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType,
571: methodName, resultTypeName, 4);
572: } else if (xmlGen) {
573: // This is for an XMLQUERY operation, so invoke the method
574: // on our execution-time object.
575: mb.callMethod(VMOpcode.INVOKEVIRTUAL, null, methodName,
576: resultTypeName, 3);
577: } else
578: mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType,
579: methodName, resultTypeName, 3);
580:
581: //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
582: if (getTypeId().variableLength())//since result type is numeric variable length, generate setWidth code.
583: {
584: if (getTypeId().isNumericTypeId()) {
585: // to leave the DataValueDescriptor value on the stack, since setWidth is void
586: mb.dup();
587:
588: mb.push(getTypeServices().getPrecision());
589: mb.push(getTypeServices().getScale());
590: mb.push(true);
591: mb.callMethod(VMOpcode.INVOKEINTERFACE,
592: ClassName.VariableSizeDataValue,
593: "setWidth", "void", 3);
594: }
595: }
596:
597: /*
598: ** Store the result of the method call in the field, so we can re-use
599: ** the object.
600: */
601:
602: mb.putField(resultField);
603: } else {
604: if (xmlGen) {
605: // This is for an XMLEXISTS operation, so invoke the method
606: // on our execution-time object.
607: mb.callMethod(VMOpcode.INVOKEVIRTUAL, null, methodName,
608: resultTypeName, 2);
609: } else {
610: mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType,
611: methodName, resultTypeName, 2);
612: }
613: }
614: }
615:
616: //following method is no-op here but in concatenation node, this method is used to check if resultField is null,
617: //and if yes, then we want it to be initialized to NULL SQLxxx type object
618: protected void initializeResultField(ExpressionClassBuilder acb,
619: MethodBuilder mb, LocalField resultField)
620: throws StandardException {
621: }
622:
623: /**
624: * Set the leftOperand to the specified ValueNode
625: *
626: * @param newLeftOperand The new leftOperand
627: */
628: public void setLeftOperand(ValueNode newLeftOperand) {
629: leftOperand = newLeftOperand;
630: }
631:
632: /**
633: * Get the leftOperand
634: *
635: * @return The current leftOperand.
636: */
637: public ValueNode getLeftOperand() {
638: return leftOperand;
639: }
640:
641: /**
642: * Set the rightOperand to the specified ValueNode
643: *
644: * @param newRightOperand The new rightOperand
645: */
646: public void setRightOperand(ValueNode newRightOperand) {
647: rightOperand = newRightOperand;
648: }
649:
650: /**
651: * Get the rightOperand
652: *
653: * @return The current rightOperand.
654: */
655: public ValueNode getRightOperand() {
656: return rightOperand;
657: }
658:
659: /**
660: * Categorize this predicate. Initially, this means
661: * building a bit map of the referenced tables for each predicate.
662: * If the source of this ColumnReference (at the next underlying level)
663: * is not a ColumnReference or a VirtualColumnNode then this predicate
664: * will not be pushed down.
665: *
666: * For example, in:
667: * select * from (select 1 from s) a (x) where x = 1
668: * we will not push down x = 1.
669: * NOTE: It would be easy to handle the case of a constant, but if the
670: * inner SELECT returns an arbitrary expression, then we would have to copy
671: * that tree into the pushed predicate, and that tree could contain
672: * subqueries and method calls.
673: * RESOLVE - revisit this issue once we have views.
674: *
675: * @param referencedTabs JBitSet with bit map of referenced FromTables
676: * @param simplePredsOnly Whether or not to consider method
677: * calls, field references and conditional nodes
678: * when building bit map
679: *
680: * @return boolean Whether or not source.expression is a ColumnReference
681: * or a VirtualColumnNode.
682: * @exception StandardException Thrown on error
683: */
684: public boolean categorize(JBitSet referencedTabs,
685: boolean simplePredsOnly) throws StandardException {
686: boolean pushable;
687: pushable = leftOperand.categorize(referencedTabs,
688: simplePredsOnly);
689: pushable = (rightOperand.categorize(referencedTabs,
690: simplePredsOnly) && pushable);
691: return pushable;
692: }
693:
694: /**
695: * Remap all ColumnReferences in this tree to be clones of the
696: * underlying expression.
697: *
698: * @return ValueNode The remapped expression tree.
699: *
700: * @exception StandardException Thrown on error
701: */
702: public ValueNode remapColumnReferencesToExpressions()
703: throws StandardException {
704: leftOperand = leftOperand.remapColumnReferencesToExpressions();
705: rightOperand = rightOperand
706: .remapColumnReferencesToExpressions();
707: return this ;
708: }
709:
710: /**
711: * Return whether or not this expression tree represents a constant expression.
712: *
713: * @return Whether or not this expression tree represents a constant expression.
714: */
715: public boolean isConstantExpression() {
716: return (leftOperand.isConstantExpression() && rightOperand
717: .isConstantExpression());
718: }
719:
720: /** @see ValueNode#constantExpression */
721: public boolean constantExpression(PredicateList whereClause) {
722: return (leftOperand.constantExpression(whereClause) && rightOperand
723: .constantExpression(whereClause));
724: }
725:
726: /**
727: * Determine the type the binary method is called on.
728: * By default, based on the receiver.
729: *
730: * Override in nodes that use methods on super-interfaces of
731: * the receiver's interface, such as comparisons.
732: *
733: * @exception StandardException Thrown on error
734: */
735: public String getReceiverInterfaceName() throws StandardException {
736: if (SanityManager.DEBUG) {
737: SanityManager
738: .ASSERT(receiver != null,
739: "can't get receiver interface name until receiver is set");
740: }
741:
742: return receiver.getTypeCompiler().interfaceName();
743: }
744:
745: /**
746: * Return the variant type for the underlying expression.
747: * The variant type can be:
748: * VARIANT - variant within a scan
749: * (method calls and non-static field access)
750: * SCAN_INVARIANT - invariant within a scan
751: * (column references from outer tables)
752: * QUERY_INVARIANT - invariant within the life of a query
753: * CONSTANT - immutable
754: *
755: * @return The variant type for the underlying expression.
756: * @exception StandardException thrown on error
757: */
758: protected int getOrderableVariantType() throws StandardException {
759: int leftType = leftOperand.getOrderableVariantType();
760: int rightType = rightOperand.getOrderableVariantType();
761:
762: return Math.min(leftType, rightType);
763: }
764:
765: /**
766: * Swap the left and right sides.
767: */
768: void swapOperands() {
769: String tmpInterfaceType = leftInterfaceType;
770: ValueNode tmpVN = leftOperand;
771:
772: leftOperand = rightOperand;
773: rightOperand = tmpVN;
774: leftInterfaceType = rightInterfaceType;
775: rightInterfaceType = tmpInterfaceType;
776: }
777:
778: /**
779: * Accept a visitor, and call v.visit()
780: * on child nodes as necessary.
781: *
782: * @param v the visitor
783: *
784: * @exception StandardException on error
785: */
786: public Visitable accept(Visitor v) throws StandardException {
787: Visitable returnNode = v.visit(this );
788:
789: if (v.skipChildren(this )) {
790: return returnNode;
791: }
792:
793: if (leftOperand != null && !v.stopTraversal()) {
794: leftOperand = (ValueNode) leftOperand.accept(v);
795: }
796:
797: if (rightOperand != null && !v.stopTraversal()) {
798: rightOperand = (ValueNode) rightOperand.accept(v);
799: }
800:
801: return returnNode;
802: }
803:
804: /**
805: * @inheritDoc
806: */
807: protected boolean isEquivalent(ValueNode o)
808: throws StandardException {
809: if (!isSameNodeType(o)) {
810: return false;
811: }
812: BinaryOperatorNode other = (BinaryOperatorNode) o;
813: return methodName.equals(other.methodName)
814: && leftOperand.isEquivalent(other.leftOperand)
815: && rightOperand.isEquivalent(other.rightOperand);
816: }
817:
818: /**
819: * Push the fields necessary to generate an instance of
820: * SqlXmlExecutor, which will then be used at execution
821: * time to retrieve the compiled XML query expression,
822: * along with any other XML-specific objects.
823: *
824: * @param acb The ExpressionClassBuilder for the class we're generating
825: * @param mb The method the code to place the code
826: *
827: * @return The number of items that this method pushed onto
828: * the mb's stack.
829: */
830: private int addXmlOpMethodParams(ExpressionClassBuilder acb,
831: MethodBuilder mb) throws StandardException {
832: // Push activation so that we can get our saved object
833: // (which will hold the compiled XML query expression)
834: // back at execute time.
835: acb.pushThisAsActivation(mb);
836:
837: // Push our saved object (the compiled query and XML-specific
838: // objects).
839: mb.push(getCompilerContext().addSavedObject(sqlxUtil));
840:
841: // We pushed 2 items to the stack.
842: return 2;
843: }
844: }
|