KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > compile > BinaryOperatorNode


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.BinaryOperatorNode
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.compile;
23
24 import org.apache.derby.iapi.sql.compile.Visitable;
25 import org.apache.derby.iapi.sql.compile.Visitor;
26 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
27 import org.apache.derby.iapi.error.StandardException;
28
29 import org.apache.derby.iapi.services.sanity.SanityManager;
30 import org.apache.derby.iapi.services.compiler.MethodBuilder;
31 import org.apache.derby.iapi.services.compiler.LocalField;
32 import org.apache.derby.iapi.services.io.StoredFormatIds;
33
34 import java.lang.reflect.Modifier JavaDoc;
35 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
36 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
37 import org.apache.derby.iapi.types.StringDataValue;
38 import org.apache.derby.iapi.types.TypeId;
39 import org.apache.derby.iapi.types.DataTypeDescriptor;
40 import org.apache.derby.iapi.types.SqlXmlUtil;
41
42 import org.apache.derby.iapi.store.access.Qualifier;
43
44 import org.apache.derby.iapi.reference.ClassName;
45 import org.apache.derby.iapi.reference.SQLState;
46
47 import org.apache.derby.iapi.util.JBitSet;
48 import org.apache.derby.iapi.services.classfile.VMOpcode;
49
50 import java.sql.Types JavaDoc;
51 import java.util.Vector JavaDoc;
52
53 /**
54  * A BinaryOperatorNode represents a built-in binary operator as defined by
55  * the ANSI/ISO SQL standard. This covers operators like +, -, *, /, =, <, etc.
56  * Java operators are not represented here: the JSQL language allows Java
57  * methods to be called from expressions, but not Java operators.
58  *
59  * @author Jeff Lichtman
60  */

61
62 public class BinaryOperatorNode extends ValueNode
63 {
64     String JavaDoc operator;
65     String JavaDoc methodName;
66     ValueNode receiver; // used in generation
67

68     /*
69     ** These identifiers are used in the grammar.
70     */

71     public final static int PLUS = 1;
72     public final static int MINUS = 2;
73     public final static int TIMES = 3;
74     public final static int DIVIDE = 4;
75     public final static int CONCATENATE = 5;
76     public final static int EQ = 6;
77     public final static int NE = 7;
78     public final static int GT = 8;
79     public final static int GE = 9;
80     public final static int LT = 10;
81     public final static int LE = 11;
82     public final static int AND = 12;
83     public final static int OR = 13;
84     public final static int LIKE = 14;
85
86     ValueNode leftOperand;
87     ValueNode rightOperand;
88
89     String JavaDoc leftInterfaceType;
90     String JavaDoc rightInterfaceType;
91     String JavaDoc resultInterfaceType;
92     int operatorType;
93
94     // At the time of adding XML support, it was decided that
95
// we should avoid creating new OperatorNodes where possible.
96
// So for the XML-related binary operators we just add the
97
// necessary code to _this_ class, similar to what is done in
98
// TernarnyOperatorNode. Subsequent binary operators (whether
99
// XML-related or not) should follow this example when
100
// possible.
101

102     public final static int XMLEXISTS_OP = 0;
103     public final static int XMLQUERY_OP = 1;
104
105     // NOTE: in the following 4 arrays, order
106
// IS important.
107

108     static final String JavaDoc[] BinaryOperators = {
109         "xmlexists",
110         "xmlquery"
111     };
112
113     static final String JavaDoc[] BinaryMethodNames = {
114         "XMLExists",
115         "XMLQuery"
116     };
117
118     static final String JavaDoc[] BinaryResultTypes = {
119         ClassName.BooleanDataValue, // XMLExists
120
ClassName.XMLDataValue // XMLQuery
121
};
122
123     static final String JavaDoc[][] BinaryArgTypes = {
124         {ClassName.StringDataValue, ClassName.XMLDataValue}, // XMLExists
125
{ClassName.StringDataValue, ClassName.XMLDataValue} // XMLQuery
126
};
127
128     // Class used to compile an XML query expression and/or load/process
129
// XML-specific objects.
130
private SqlXmlUtil sqlxUtil;
131
132     /**
133      * Initializer for a BinaryOperatorNode
134      *
135      * @param leftOperand The left operand of the node
136      * @param rightOperand The right operand of the node
137      * @param operator The name of the operator
138      * @param methodName The name of the method to call for this operator
139      * @param leftInterfaceType The name of the interface for the left operand
140      * @param rightInterfaceType The name of the interface for the right
141      * operand
142      */

143
144     public void init(
145             Object JavaDoc leftOperand,
146             Object JavaDoc rightOperand,
147             Object JavaDoc operator,
148             Object JavaDoc methodName,
149             Object JavaDoc leftInterfaceType,
150             Object JavaDoc rightInterfaceType)
151     {
152         this.leftOperand = (ValueNode) leftOperand;
153         this.rightOperand = (ValueNode) rightOperand;
154         this.operator = (String JavaDoc) operator;
155         this.methodName = (String JavaDoc) methodName;
156         this.leftInterfaceType = (String JavaDoc) leftInterfaceType;
157         this.rightInterfaceType = (String JavaDoc) rightInterfaceType;
158         this.operatorType = -1;
159     }
160
161     public void init(
162             Object JavaDoc leftOperand,
163             Object JavaDoc rightOperand,
164             Object JavaDoc leftInterfaceType,
165             Object JavaDoc rightInterfaceType)
166     {
167         this.leftOperand = (ValueNode) leftOperand;
168         this.rightOperand = (ValueNode) rightOperand;
169         this.leftInterfaceType = (String JavaDoc) leftInterfaceType;
170         this.rightInterfaceType = (String JavaDoc) rightInterfaceType;
171         this.operatorType = -1;
172     }
173
174     /**
175      * Initializer for a BinaryOperatorNode
176      *
177      * @param leftOperand The left operand of the node
178      * @param rightOperand The right operand of the node
179      * @param opType An Integer holding the operatorType
180      * for this operator.
181      */

182     public void init(
183             Object JavaDoc leftOperand,
184             Object JavaDoc rightOperand,
185             Object JavaDoc opType)
186     {
187         this.leftOperand = (ValueNode)leftOperand;
188         this.rightOperand = (ValueNode)rightOperand;
189         this.operatorType = ((Integer JavaDoc)opType).intValue();
190         this.operator = BinaryOperators[this.operatorType];
191         this.methodName = BinaryMethodNames[this.operatorType];
192         this.leftInterfaceType = BinaryArgTypes[this.operatorType][0];
193         this.rightInterfaceType = BinaryArgTypes[this.operatorType][1];
194         this.resultInterfaceType = BinaryResultTypes[this.operatorType];
195     }
196
197     /**
198      * Convert this object to a String. See comments in QueryTreeNode.java
199      * for how this should be done for tree printing.
200      *
201      * @return This object as a String
202      */

203
204     public String JavaDoc toString()
205     {
206         if (SanityManager.DEBUG)
207         {
208             return "operator: " + operator + "\n" +
209                 "methodName: " + methodName + "\n" +
210                 super.toString();
211         }
212         else
213         {
214             return "";
215         }
216     }
217
218     /**
219      * Set the operator.
220      *
221      * @param operator The operator.
222      */

223     void setOperator(String JavaDoc operator)
224     {
225         this.operator = operator;
226         this.operatorType = -1;
227     }
228
229     /**
230      * Set the methodName.
231      *
232      * @param methodName The methodName.
233      */

234     void setMethodName(String JavaDoc methodName)
235     {
236         this.methodName = methodName;
237         this.operatorType = -1;
238     }
239
240     /**
241      * Set the interface type for the left and right arguments.
242      * Used when we don't know the interface type until
243      * later in binding.
244      */

245     public void setLeftRightInterfaceType(String JavaDoc iType)
246     {
247         leftInterfaceType = iType;
248         rightInterfaceType = iType;
249         this.operatorType = -1;
250     }
251
252     /**
253      * Set the clause that this node appears in.
254      *
255      * @param clause The clause that this node appears in.
256      */

257     public void setClause(int clause)
258     {
259         super.setClause(clause);
260         leftOperand.setClause(clause);
261         rightOperand.setClause(clause);
262     }
263
264     /**
265      * Prints the sub-nodes of this object. See QueryTreeNode.java for
266      * how tree printing is supposed to work.
267      *
268      * @param depth The depth of this node in the tree
269      */

270
271     public void printSubNodes(int depth)
272     {
273         if (SanityManager.DEBUG)
274         {
275             super.printSubNodes(depth);
276
277             if (leftOperand != null)
278             {
279                 printLabel(depth, "leftOperand: ");
280                 leftOperand.treePrint(depth + 1);
281             }
282
283             if (rightOperand != null)
284             {
285                 printLabel(depth, "rightOperand: ");
286                 rightOperand.treePrint(depth + 1);
287             }
288         }
289     }
290
291     /**
292      * Bind this expression. This means binding the sub-expressions,
293      * as well as figuring out what the return type is for this expression.
294      *
295      * @param fromList The FROM list for the query this
296      * expression is in, for binding columns.
297      * @param subqueryList The subquery list being built as we find SubqueryNodes
298      * @param aggregateVector The aggregate vector being built as we find AggregateNodes
299      *
300      * @return The new top of the expression tree.
301      *
302      * @exception StandardException Thrown on error
303      */

304
305     public ValueNode bindExpression(
306         FromList fromList, SubqueryList subqueryList,
307         Vector JavaDoc aggregateVector)
308             throws StandardException
309     {
310         leftOperand = leftOperand.bindExpression(fromList, subqueryList,
311             aggregateVector);
312         rightOperand = rightOperand.bindExpression(fromList, subqueryList,
313             aggregateVector);
314
315         if ((operatorType == XMLEXISTS_OP) || (operatorType == XMLQUERY_OP))
316             return bindXMLQuery();
317
318         /* Is there a ? parameter on the left? */
319         if (leftOperand.requiresTypeFromContext())
320         {
321             /*
322             ** It's an error if both operands are ? parameters.
323             */

324             if (rightOperand.requiresTypeFromContext())
325             {
326                 throw StandardException.newException(SQLState.LANG_BINARY_OPERANDS_BOTH_PARMS,
327                                                                     operator);
328             }
329
330             /* Set the left operand to the type of right parameter. */
331             leftOperand.setType(rightOperand.getTypeServices());
332         }
333
334         /* Is there a ? parameter on the right? */
335         if (rightOperand.requiresTypeFromContext())
336         {
337             /* Set the right operand to the type of the left parameter. */
338             rightOperand.setType(leftOperand.getTypeServices());
339         }
340
341         return genSQLJavaSQLTree();
342     }
343
344     /**
345      * Bind an XMLEXISTS or XMLQUERY operator. Makes sure
346      * the operand type and target type are both correct
347      * and sets the result type.
348      *
349      * @exception StandardException Thrown on error
350      */

351     public ValueNode bindXMLQuery()
352         throws StandardException
353     {
354         // Check operand types.
355
TypeId leftOperandType = leftOperand.getTypeId();
356         TypeId rightOperandType = rightOperand.getTypeId();
357
358         // Left operand is query expression and must be a string
359
// literal. SQL/XML spec doesn't allow params nor expressions
360
// 6.17: <XQuery expression> ::= <character string literal>
361
if (!(leftOperand instanceof CharConstantNode))
362         {
363             throw StandardException.newException(
364                 SQLState.LANG_INVALID_XML_QUERY_EXPRESSION);
365         }
366         else {
367         // compile the query expression.
368
sqlxUtil = new SqlXmlUtil();
369             sqlxUtil.compileXQExpr(
370                 ((CharConstantNode)leftOperand).getString(),
371                 (operatorType == XMLEXISTS_OP ? "XMLEXISTS" : "XMLQUERY"));
372         }
373
374         // Right operand must be an XML data value. NOTE: This
375
// is a Derby-specific restriction, not an SQL/XML one.
376
// We have this restriction because the query engine
377
// that we use (currently Xalan) cannot handle non-XML
378
// context items.
379
if ((rightOperandType != null) &&
380             !rightOperandType.isXMLTypeId())
381         {
382             throw StandardException.newException(
383                 SQLState.LANG_INVALID_CONTEXT_ITEM_TYPE,
384                 rightOperandType.getSQLTypeName());
385         }
386
387         // Is there a ? parameter on the right?
388
if (rightOperand.requiresTypeFromContext())
389         {
390             // For now, since JDBC has no type defined for XML, we
391
// don't allow binding to an XML parameter.
392
throw StandardException.newException(
393                 SQLState.LANG_ATTEMPT_TO_BIND_XML);
394         }
395
396         // Set the result type of this operator.
397
if (operatorType == XMLEXISTS_OP) {
398         // For XMLEXISTS, the result type is always SQLBoolean.
399
// The "true" in the next line says that the result
400
// can be nullable--which it can be if evaluation of
401
// the expression returns a null (this is per SQL/XML
402
// spec, 8.4)
403
setType(new DataTypeDescriptor(TypeId.BOOLEAN_ID, true));
404         }
405         else {
406         // The result of an XMLQUERY operator is always another
407
// XML data value, per SQL/XML spec 6.17: "...yielding a value
408
// X1 of an XML type."
409
setType(DataTypeDescriptor.getBuiltInDataTypeDescriptor(
410                 StoredFormatIds.XML_TYPE_ID));
411         }
412
413         return genSQLJavaSQLTree();
414     }
415
416     /** generate a SQL->Java->SQL conversion tree above the left and right
417      * operand of this Binary Operator Node if needed. Subclasses can override
418      * the default behavior.
419      */

420     public ValueNode genSQLJavaSQLTree() throws StandardException
421     {
422         TypeId leftTypeId = leftOperand.getTypeId();
423         
424         if (leftTypeId.userType())
425             leftOperand = leftOperand.genSQLJavaSQLTree();
426
427         TypeId rightTypeId = rightOperand.getTypeId();
428         if (rightTypeId.userType())
429             rightOperand = rightOperand.genSQLJavaSQLTree();
430
431         return this;
432     }
433
434     /**
435      * Preprocess an expression tree. We do a number of transformations
436      * here (including subqueries, IN lists, LIKE and BETWEEN) plus
437      * subquery flattening.
438      * NOTE: This is done before the outer ResultSetNode is preprocessed.
439      *
440      * @param numTables Number of tables in the DML Statement
441      * @param outerFromList FromList from outer query block
442      * @param outerSubqueryList SubqueryList from outer query block
443      * @param outerPredicateList PredicateList from outer query block
444      *
445      * @return The modified expression
446      *
447      * @exception StandardException Thrown on error
448      */

449     public ValueNode preprocess(int numTables,
450                                 FromList outerFromList,
451                                 SubqueryList outerSubqueryList,
452                                 PredicateList outerPredicateList)
453                     throws StandardException
454     {
455         leftOperand = leftOperand.preprocess(numTables,
456                                              outerFromList, outerSubqueryList,
457                                              outerPredicateList);
458         rightOperand = rightOperand.preprocess(numTables,
459                                                outerFromList, outerSubqueryList,
460                                                outerPredicateList);
461         return this;
462     }
463
464     /**
465      * Do code generation for this binary operator.
466      *
467      * @param acb The ExpressionClassBuilder for the class we're generating
468      * @param mb The method the code to place the code
469      *
470      *
471      * @exception StandardException Thrown on error
472      */

473
474     public void generateExpression(ExpressionClassBuilder acb,
475                                             MethodBuilder mb)
476         throws StandardException
477     {
478         String JavaDoc resultTypeName;
479         String JavaDoc receiverType;
480
481 /*
482 ** if i have a operator.getOrderableType() == constant, then just cache
483 ** it in a field. if i have QUERY_INVARIANT, then it would be good to
484 ** cache it in something that is initialized each execution,
485 ** but how?
486 */

487
488         // If we're dealing with XMLEXISTS or XMLQUERY, there is some
489
// additional work to be done.
490
boolean xmlGen =
491             (operatorType == XMLQUERY_OP) || (operatorType == XMLEXISTS_OP);
492
493         if (xmlGen) {
494         // We create an execution-time object so that we can retrieve
495
// saved objects (esp. our compiled query expression) from
496
// the activation. We do this for two reasons: 1) this level
497
// of indirection allows us to separate the XML data type
498
// from the required XML implementation classes (esp. JAXP
499
// and Xalan classes)--for more on how this works, see the
500
// comments in SqlXmlUtil.java; and 2) we can take
501
// the XML query expression, which we've already compiled,
502
// and pass it to the execution-time object for each row,
503
// which means that we only have to compile the query
504
// expression once per SQL statement (instead of once per
505
// row); see SqlXmlExecutor.java for more.
506
mb.pushNewStart(
507                 "org.apache.derby.impl.sql.execute.SqlXmlExecutor");
508             mb.pushNewComplete(addXmlOpMethodParams(acb, mb));
509         }
510
511         /*
512         ** The receiver is the operand with the higher type precedence.
513         ** Like always makes the left the receiver.
514         **
515         */

516         if (leftOperand.getTypeId().typePrecedence() >
517             rightOperand.getTypeId().typePrecedence())
518         {
519             receiver = leftOperand;
520             /*
521             ** let the receiver type be determined by an
522             ** overridable method so that if methods are
523             ** not implemented on the lowest interface of
524             ** a class, they can note that in the implementation
525             ** of the node that uses the method.
526             */

527             receiverType = (operatorType == -1)
528                 ? getReceiverInterfaceName()
529                 : leftInterfaceType;
530
531             /*
532             ** Generate (with <left expression> only being evaluated once)
533             **
534             ** <left expression>.method(<left expression>, <right expression>...)
535             */

536
537             leftOperand.generateExpression(acb, mb);
538             mb.cast(receiverType); // cast the method instance
539
// stack: left
540

541             mb.dup();
542             mb.cast(leftInterfaceType);
543             // stack: left, left
544

545             rightOperand.generateExpression(acb, mb);
546             mb.cast(rightInterfaceType); // second arg with cast
547
// stack: left, left, right
548
}
549         else
550         {
551             receiver = rightOperand;
552             /*
553             ** let the receiver type be determined by an
554             ** overridable method so that if methods are
555             ** not implemented on the lowest interface of
556             ** a class, they can note that in the implementation
557             ** of the node that uses the method.
558             */

559             receiverType = (operatorType == -1)
560                 ? getReceiverInterfaceName()
561                 : rightInterfaceType;
562
563             /*
564             ** Generate (with <right expression> only being evaluated once)
565             **
566             ** <right expression>.method(<left expression>, <right expression>)
567             **
568             ** UNLESS we're generating an XML operator such as XMLEXISTS.
569             ** In that case we want to generate
570             **
571             ** SqlXmlExecutor.method(left, right)"
572             **
573             ** and we've already pushed the SqlXmlExecutor object to
574             ** the stack.
575             */

576
577             rightOperand.generateExpression(acb, mb);
578             mb.cast(receiverType); // cast the method instance
579
// stack: right
580

581             if (!xmlGen) {
582                 mb.dup();
583                 mb.cast(rightInterfaceType);
584                 // stack: right,right
585
}
586             
587             leftOperand.generateExpression(acb, mb);
588             mb.cast(leftInterfaceType); // second arg with cast
589
// stack: right,right,left
590

591             mb.swap();
592             // stack: right,left,right
593
}
594
595         /* Figure out the result type name */
596         resultTypeName = (operatorType == -1)
597             ? getTypeCompiler().interfaceName()
598             : resultInterfaceType;
599
600         // Boolean return types don't need a result field
601
boolean needField = !getTypeId().isBooleanTypeId();
602
603         if (needField) {
604
605             /* Allocate an object for re-use to hold the result of the operator */
606             LocalField resultField =
607                 acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);
608
609             /*
610             ** Call the method for this operator.
611             */

612             mb.getField(resultField); // third arg
613
//following method is special code for concatenation where if field is null, we want it to be initialized to NULL SQLxxx type object
614
//before generating code "field = method(p1, p2, field);"
615
initializeResultField(acb, mb, resultField);
616
617             /* pass statically calculated scale to decimal divide method to make
618              * result set scale consistent, beetle 3901
619              */

620             int jdbcType;
621             if ((dataTypeServices != null) &&
622                 ((jdbcType = dataTypeServices.getJDBCTypeId()) == java.sql.Types.DECIMAL ||
623                  jdbcType == java.sql.Types.NUMERIC) &&
624                 operator.equals("/"))
625             {
626                 mb.push(dataTypeServices.getScale()); // 4th arg
627
mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, 4);
628             }
629             else if (xmlGen) {
630             // This is for an XMLQUERY operation, so invoke the method
631
// on our execution-time object.
632
mb.callMethod(VMOpcode.INVOKEVIRTUAL, null,
633                     methodName, resultTypeName, 3);
634             }
635             else
636                 mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, 3);
637
638             //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
639
if (getTypeId().variableLength())//since result type is numeric variable length, generate setWidth code.
640
{
641                 if (getTypeId().isNumericTypeId())
642                 {
643                     // to leave the DataValueDescriptor value on the stack, since setWidth is void
644
mb.dup();
645
646                     mb.push(getTypeServices().getPrecision());
647                     mb.push(getTypeServices().getScale());
648                     mb.push(true);
649                     mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue, "setWidth", "void", 3);
650                 }
651             }
652
653
654             /*
655             ** Store the result of the method call in the field, so we can re-use
656             ** the object.
657             */

658
659             mb.putField(resultField);
660         } else {
661             if (xmlGen) {
662             // This is for an XMLEXISTS operation, so invoke the method
663
// on our execution-time object.
664
mb.callMethod(VMOpcode.INVOKEVIRTUAL, null,
665                     methodName, resultTypeName, 2);
666             }
667             else {
668                 mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType,
669                     methodName, resultTypeName, 2);
670             }
671         }
672     }
673
674     //following method is no-op here but in concatenation node, this method is used to check if resultField is null,
675
//and if yes, then we want it to be initialized to NULL SQLxxx type object
676
protected void initializeResultField(ExpressionClassBuilder acb, MethodBuilder mb, LocalField resultField)
677     throws StandardException
678     {
679     }
680
681     /**
682      * Set the leftOperand to the specified ValueNode
683      *
684      * @param newLeftOperand The new leftOperand
685      */

686     public void setLeftOperand(ValueNode newLeftOperand)
687     {
688         leftOperand = newLeftOperand;
689     }
690
691     /**
692      * Get the leftOperand
693      *
694      * @return The current leftOperand.
695      */

696     public ValueNode getLeftOperand()
697     {
698         return leftOperand;
699     }
700
701     /**
702      * Set the rightOperand to the specified ValueNode
703      *
704      * @param newRightOperand The new rightOperand
705      */

706     public void setRightOperand(ValueNode newRightOperand)
707     {
708         rightOperand = newRightOperand;
709     }
710
711     /**
712      * Get the rightOperand
713      *
714      * @return The current rightOperand.
715      */

716     public ValueNode getRightOperand()
717     {
718         return rightOperand;
719     }
720
721     /**
722      * Categorize this predicate. Initially, this means
723      * building a bit map of the referenced tables for each predicate.
724      * If the source of this ColumnReference (at the next underlying level)
725      * is not a ColumnReference or a VirtualColumnNode then this predicate
726      * will not be pushed down.
727      *
728      * For example, in:
729      * select * from (select 1 from s) a (x) where x = 1
730      * we will not push down x = 1.
731      * NOTE: It would be easy to handle the case of a constant, but if the
732      * inner SELECT returns an arbitrary expression, then we would have to copy
733      * that tree into the pushed predicate, and that tree could contain
734      * subqueries and method calls.
735      * RESOLVE - revisit this issue once we have views.
736      *
737      * @param referencedTabs JBitSet with bit map of referenced FromTables
738      * @param simplePredsOnly Whether or not to consider method
739      * calls, field references and conditional nodes
740      * when building bit map
741      *
742      * @return boolean Whether or not source.expression is a ColumnReference
743      * or a VirtualColumnNode.
744      * @exception StandardException Thrown on error
745      */

746     public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)
747         throws StandardException
748     {
749         boolean pushable;
750         pushable = leftOperand.categorize(referencedTabs, simplePredsOnly);
751         pushable = (rightOperand.categorize(referencedTabs, simplePredsOnly) && pushable);
752         return pushable;
753     }
754
755     /**
756      * Remap all ColumnReferences in this tree to be clones of the
757      * underlying expression.
758      *
759      * @return ValueNode The remapped expression tree.
760      *
761      * @exception StandardException Thrown on error
762      */

763     public ValueNode remapColumnReferencesToExpressions()
764         throws StandardException
765     {
766         leftOperand = leftOperand.remapColumnReferencesToExpressions();
767         rightOperand = rightOperand.remapColumnReferencesToExpressions();
768         return this;
769     }
770
771     /**
772      * Return whether or not this expression tree represents a constant expression.
773      *
774      * @return Whether or not this expression tree represents a constant expression.
775      */

776     public boolean isConstantExpression()
777     {
778         return (leftOperand.isConstantExpression() &&
779                 rightOperand.isConstantExpression());
780     }
781
782     /** @see ValueNode#constantExpression */
783     public boolean constantExpression(PredicateList whereClause)
784     {
785         return (leftOperand.constantExpression(whereClause) &&
786                 rightOperand.constantExpression(whereClause));
787     }
788
789     /**
790      * Determine the type the binary method is called on.
791      * By default, based on the receiver.
792      *
793      * Override in nodes that use methods on super-interfaces of
794      * the receiver's interface, such as comparisons.
795      *
796      * @exception StandardException Thrown on error
797      */

798     public String JavaDoc getReceiverInterfaceName() throws StandardException {
799         if (SanityManager.DEBUG)
800         {
801             SanityManager.ASSERT(receiver!=null,"can't get receiver interface name until receiver is set");
802         }
803
804         return receiver.getTypeCompiler().interfaceName();
805     }
806
807     /**
808      * Return the variant type for the underlying expression.
809      * The variant type can be:
810      * VARIANT - variant within a scan
811      * (method calls and non-static field access)
812      * SCAN_INVARIANT - invariant within a scan
813      * (column references from outer tables)
814      * QUERY_INVARIANT - invariant within the life of a query
815      * CONSTANT - immutable
816      *
817      * @return The variant type for the underlying expression.
818      * @exception StandardException thrown on error
819      */

820     protected int getOrderableVariantType() throws StandardException
821     {
822         int leftType = leftOperand.getOrderableVariantType();
823         int rightType = rightOperand.getOrderableVariantType();
824
825         return Math.min(leftType, rightType);
826     }
827
828     /**
829      * Swap the left and right sides.
830      */

831     void swapOperands()
832     {
833         String JavaDoc tmpInterfaceType = leftInterfaceType;
834         ValueNode tmpVN = leftOperand;
835
836         leftOperand = rightOperand;
837         rightOperand = tmpVN;
838         leftInterfaceType = rightInterfaceType;
839         rightInterfaceType = tmpInterfaceType;
840     }
841
842     /**
843      * Accept a visitor, and call v.visit()
844      * on child nodes as necessary.
845      *
846      * @param v the visitor
847      *
848      * @exception StandardException on error
849      */

850     public Visitable accept(Visitor v)
851         throws StandardException
852     {
853         Visitable returnNode = v.visit(this);
854     
855         if (v.skipChildren(this))
856         {
857             return returnNode;
858         }
859
860         if (leftOperand != null && !v.stopTraversal())
861         {
862             leftOperand = (ValueNode)leftOperand.accept(v);
863         }
864
865         if (rightOperand != null && !v.stopTraversal())
866         {
867             rightOperand = (ValueNode)rightOperand.accept(v);
868         }
869         
870         return returnNode;
871     }
872
873         /**
874          * @inheritDoc
875          */

876         protected boolean isEquivalent(ValueNode o) throws StandardException
877         {
878             if (!isSameNodeType(o))
879             {
880                 return false;
881             }
882             BinaryOperatorNode other = (BinaryOperatorNode)o;
883             return methodName.equals(other.methodName)
884                    && leftOperand.isEquivalent(other.leftOperand)
885                    && rightOperand.isEquivalent(other.rightOperand);
886         }
887
888     /**
889      * Push the fields necessary to generate an instance of
890      * SqlXmlExecutor, which will then be used at execution
891      * time to retrieve the compiled XML query expression,
892      * along with any other XML-specific objects.
893      *
894      * @param acb The ExpressionClassBuilder for the class we're generating
895      * @param mb The method the code to place the code
896      *
897      * @return The number of items that this method pushed onto
898      * the mb's stack.
899      */

900     private int addXmlOpMethodParams(ExpressionClassBuilder acb,
901         MethodBuilder mb) throws StandardException
902     {
903         // Push activation so that we can get our saved object
904
// (which will hold the compiled XML query expression)
905
// back at execute time.
906
acb.pushThisAsActivation(mb);
907
908         // Push our saved object (the compiled query and XML-specific
909
// objects).
910
mb.push(getCompilerContext().addSavedObject(sqlxUtil));
911
912         // We pushed 2 items to the stack.
913
return 2;
914     }
915 }
916
Popular Tags