KickJava   Java API By Example, From Geeks To Geeks.

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


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

60
61 public class UnaryOperatorNode extends ValueNode
62 {
63     String JavaDoc operator;
64     String JavaDoc methodName;
65     int operatorType;
66
67     String JavaDoc resultInterfaceType;
68     String JavaDoc receiverInterfaceType;
69
70     /**
71      * WARNING: operand may be NULL for COUNT(*).
72      */

73     ValueNode operand;
74
75     public final static int UNARY_PLUS = 1;
76     public final static int UNARY_MINUS = 2;
77     public final static int NOT = 3;
78     public final static int IS_NULL = 4;
79
80     // At the time of adding XML support, it was decided that
81
// we should avoid creating new OperatorNodes where possible.
82
// So for the XML-related unary operators we just add the
83
// necessary code to _this_ class, similar to what is done in
84
// TernarnyOperatorNode. Subsequent unary operators (whether
85
// XML-related or not) should follow this example when
86
// possible.
87

88     public final static int XMLPARSE_OP = 0;
89     public final static int XMLSERIALIZE_OP = 1;
90
91     // NOTE: in the following 4 arrays, order
92
// IS important.
93

94     static final String JavaDoc[] UnaryOperators = {
95         "xmlparse",
96         "xmlserialize"
97     };
98
99     static final String JavaDoc[] UnaryMethodNames = {
100         "XMLParse",
101         "XMLSerialize"
102     };
103
104     static final String JavaDoc[] UnaryResultTypes = {
105         ClassName.XMLDataValue, // XMLParse
106
ClassName.StringDataValue // XMLSerialize
107
};
108
109     static final String JavaDoc[] UnaryArgTypes = {
110         ClassName.StringDataValue, // XMLParse
111
ClassName.XMLDataValue // XMLSerialize
112
};
113
114     // Array to hold Objects that contain primitive
115
// args required by the operator method call.
116
private Object JavaDoc [] additionalArgs;
117
118     // Class used to hold XML-specific objects required for
119
// parsing/serializing XML data.
120
private SqlXmlUtil sqlxUtil;
121
122     /**
123      * Initializer for a UnaryOperatorNode.
124      *
125      * <ul>
126      * @param operand The operand of the node
127      * @param operatorOrOpType Either 1) the name of the operator,
128      * OR 2) an Integer holding the operatorType for this operator.
129      * @param methodNameOrAddedArgs Either 1) name of the method
130      * to call for this operator, or 2) an array of Objects
131      * from which primitive method parameters can be
132      * retrieved.
133      */

134
135     public void init(
136                     Object JavaDoc operand,
137                     Object JavaDoc operatorOrOpType,
138                     Object JavaDoc methodNameOrAddedArgs)
139     {
140         this.operand = (ValueNode) operand;
141         if (operatorOrOpType instanceof String JavaDoc) {
142         // then 2nd and 3rd params are operator and methodName,
143
// respectively.
144
this.operator = (String JavaDoc) operatorOrOpType;
145             this.methodName = (String JavaDoc) methodNameOrAddedArgs;
146             this.operatorType = -1;
147         }
148         else {
149         // 2nd and 3rd params are operatorType and additional args,
150
// respectively.
151
if (SanityManager.DEBUG) {
152                 SanityManager.ASSERT(
153                     ((operatorOrOpType instanceof Integer JavaDoc) &&
154                         ((methodNameOrAddedArgs == null) ||
155                         (methodNameOrAddedArgs instanceof Object JavaDoc[]))),
156                     "Init params in UnaryOperator node have the " +
157                     "wrong type.");
158             }
159             this.operatorType = ((Integer JavaDoc) operatorOrOpType).intValue();
160             this.operator = UnaryOperators[this.operatorType];
161             this.methodName = UnaryMethodNames[this.operatorType];
162             this.resultInterfaceType = UnaryResultTypes[this.operatorType];
163             this.receiverInterfaceType = UnaryArgTypes[this.operatorType];
164             this.additionalArgs = (Object JavaDoc[])methodNameOrAddedArgs;
165         }
166     }
167
168     /**
169      * Initializer for a UnaryOperatorNode
170      *
171      * @param operand The operand of the node
172      */

173     public void init(Object JavaDoc operand)
174     {
175         this.operand = (ValueNode) operand;
176         this.operatorType = -1;
177     }
178
179     /**
180      * Set the operator.
181      *
182      * @param operator The operator.
183      */

184     void setOperator(String JavaDoc operator)
185     {
186         this.operator = operator;
187         this.operatorType = -1;
188     }
189
190     /**
191      * Get the operator of this unary operator.
192      *
193      * @return The operator of this unary operator.
194      */

195     String JavaDoc getOperatorString()
196     {
197         return operator;
198     }
199
200     /**
201      * Set the methodName.
202      *
203      * @param methodName The methodName.
204      */

205     void setMethodName(String JavaDoc methodName)
206     {
207         this.methodName = methodName;
208         this.operatorType = -1;
209     }
210
211     /**
212      * Convert this object to a String. See comments in QueryTreeNode.java
213      * for how this should be done for tree printing.
214      *
215      * @return This object as a String
216      */

217
218     public String JavaDoc toString()
219     {
220         if (SanityManager.DEBUG)
221         {
222             return "operator: " + operator + "\n" +
223                 "methodName: " + methodName + "\n" +
224                 super.toString();
225         }
226         else
227         {
228             return "";
229         }
230     }
231
232     /**
233      * Prints the sub-nodes of this object. See QueryTreeNode.java for
234      * how tree printing is supposed to work.
235      *
236      * @param depth The depth of this node in the tree
237      */

238
239     public void printSubNodes(int depth)
240     {
241         if (SanityManager.DEBUG)
242         {
243             super.printSubNodes(depth);
244
245             if (operand != null)
246             {
247                 printLabel(depth, "operand: ");
248                 operand.treePrint(depth + 1);
249             }
250         }
251     }
252
253     /**
254      * Get the operand of this unary operator.
255      *
256      * @return The operand of this unary operator.
257      */

258     public ValueNode getOperand()
259     {
260         return operand;
261     }
262
263     /**
264      * Get the parameter operand of this unary operator.
265      * For the example below, for abs unary operator node, we want to get ?
266      * select * from t1 where -? = max_cni(abs(-?), sqrt(+?))
267      *
268      * This gets called when ParameterNode is needed to get parameter
269      * specific information like getDefaultValue(), getParameterNumber() etc
270      *
271      * @return The parameter operand of this unary operator else null.
272      */

273     public ParameterNode getParameterOperand()
274     {
275         if (requiresTypeFromContext() == false)
276             return null;
277         else {
278             UnaryOperatorNode tempUON = this;
279             while (!(tempUON.getOperand() instanceof ParameterNode))
280                 tempUON = (UnaryOperatorNode)tempUON.getOperand();
281             return (ParameterNode)(tempUON.getOperand());
282         }
283     }
284
285     /**
286      * Set the clause that this node appears in.
287      *
288      * @param clause The clause that this node appears in.
289      */

290     public void setClause(int clause)
291     {
292         super.setClause(clause);
293
294         /*
295         ** Operator may be null for COUNT(*)
296         */

297         if (operand != null)
298         {
299             operand.setClause(clause);
300         }
301     }
302
303     /**
304      * Bind this expression. This means binding the sub-expressions,
305      * as well as figuring out what the return type is for this expression.
306      *
307      * @param fromList The FROM list for the query this
308      * expression is in, for binding columns.
309      * @param subqueryList The subquery list being built as we find SubqueryNodes
310      * @param aggregateVector The aggregate vector being built as we find AggregateNodes
311      *
312      * @return The new top of the expression tree.
313      *
314      * @exception StandardException Thrown on error
315      */

316
317     public ValueNode bindExpression(
318                     FromList fromList, SubqueryList subqueryList,
319                     Vector JavaDoc aggregateVector)
320                 throws StandardException
321     {
322         return bindUnaryOperator(fromList, subqueryList, aggregateVector);
323     }
324
325     /**
326      * Workhorse for bindExpression. This exists so it can be called
327      * by child classes.
328      */

329     protected ValueNode bindUnaryOperator(
330                     FromList fromList, SubqueryList subqueryList,
331                     Vector JavaDoc aggregateVector)
332                 throws StandardException
333     {
334         /*
335         ** Operand can be null for COUNT(*) which
336         ** is treated like a normal aggregate.
337         */

338         if (operand == null)
339         {
340             return this;
341         }
342
343         //Return with no binding, if the type of unary minus/plus parameter is not set yet.
344
if (operand.requiresTypeFromContext() && ((operator.equals("-") || operator.equals("+"))) && operand.getTypeServices() == null)
345             return this;
346
347         operand = operand.bindExpression(fromList, subqueryList,
348                                 aggregateVector);
349
350         if (operand.requiresTypeFromContext())
351             bindParameter();
352
353         /* If the operand is not a built-in type, then generate a bound conversion
354          * tree to a built-in type.
355          */

356         if (! (operand instanceof UntypedNullConstantNode) &&
357             operand.getTypeId().userType() &&
358             ! (this instanceof IsNullNode))
359         {
360             operand = operand.genSQLJavaSQLTree();
361         }
362
363         if (operatorType == XMLPARSE_OP)
364             bindXMLParse();
365         else if (operatorType == XMLSERIALIZE_OP)
366             bindXMLSerialize();
367
368         return this;
369     }
370
371     /**
372      * Bind an XMLPARSE operator. Makes sure the operand type
373      * is correct, and sets the result type.
374      *
375      * @exception StandardException Thrown on error
376      */

377     public void bindXMLParse() throws StandardException
378     {
379         // Check the type of the operand - this function is allowed only on
380
// string value (char) types.
381
TypeId operandType = operand.getTypeId();
382         if (operandType != null) {
383             switch (operandType.getJDBCTypeId())
384             {
385                 case Types.CHAR:
386                 case Types.VARCHAR:
387                 case Types.LONGVARCHAR:
388                 case Types.CLOB:
389                     break;
390                 default:
391                 {
392                     throw StandardException.newException(
393                         SQLState.LANG_UNARY_FUNCTION_BAD_TYPE,
394                         methodName,
395                         operandType.getSQLTypeName());
396                 }
397             }
398         }
399
400         // Create a new XML compiler object; the constructor
401
// here automatically creates the XML-specific objects
402
// required for parsing/serializing XML, so all we
403
// have to do is create an instance.
404
sqlxUtil = new SqlXmlUtil();
405
406         // The result type of XMLParse() is always an XML type.
407
setType(DataTypeDescriptor.getBuiltInDataTypeDescriptor(
408             StoredFormatIds.XML_TYPE_ID));
409     }
410
411     /**
412      * Bind an XMLSERIALIZE operator. Makes sure the operand type
413      * and target type are both correct, and sets the result type.
414      *
415      * @exception StandardException Thrown on error
416      */

417     public void bindXMLSerialize() throws StandardException
418     {
419         TypeId operandType;
420
421         // Check the type of the operand - this function is allowed only on
422
// the XML type.
423
operandType = operand.getTypeId();
424         if ((operandType != null) && !operandType.isXMLTypeId())
425         {
426             throw StandardException.newException(
427                 SQLState.LANG_UNARY_FUNCTION_BAD_TYPE,
428                 methodName,
429                 operandType.getSQLTypeName());
430         }
431
432         // Check the target type. We only allow string types to be used as
433
// the target type. The targetType is stored as the first Object
434
// in our list of additional parameters, so we have to retrieve
435
// it from there.
436
if (SanityManager.DEBUG) {
437             SanityManager.ASSERT(
438                 ((additionalArgs != null) && (additionalArgs.length > 0)),
439                 "Failed to locate target type for XMLSERIALIZE operator");
440         }
441
442         DataTypeDescriptor targetType =
443             (DataTypeDescriptor)additionalArgs[0];
444
445         TypeId targetTypeId = targetType.getTypeId();
446         switch (targetTypeId.getJDBCTypeId())
447         {
448             case Types.CHAR:
449             case Types.VARCHAR:
450             case Types.LONGVARCHAR:
451             case Types.CLOB:
452                 break;
453             default:
454             {
455                 throw StandardException.newException(
456                     SQLState.LANG_INVALID_XMLSERIALIZE_TYPE,
457                     targetTypeId.getSQLTypeName());
458             }
459         }
460
461         // The result type of XMLSerialize() is always a string; which
462
// kind of string is determined by the targetType field.
463
setType(targetType);
464     }
465
466     /**
467      * Preprocess an expression tree. We do a number of transformations
468      * here (including subqueries, IN lists, LIKE and BETWEEN) plus
469      * subquery flattening.
470      * NOTE: This is done before the outer ResultSetNode is preprocessed.
471      *
472      * @param numTables Number of tables in the DML Statement
473      * @param outerFromList FromList from outer query block
474      * @param outerSubqueryList SubqueryList from outer query block
475      * @param outerPredicateList PredicateList from outer query block
476      *
477      * @return The modified expression
478      *
479      * @exception StandardException Thrown on error
480      */

481     public ValueNode preprocess(int numTables,
482                                 FromList outerFromList,
483                                 SubqueryList outerSubqueryList,
484                                 PredicateList outerPredicateList)
485                     throws StandardException
486     {
487         if (operand != null)
488         {
489             operand = operand.preprocess(numTables,
490                                          outerFromList, outerSubqueryList,
491                                          outerPredicateList);
492         }
493         return this;
494     }
495
496     /**
497      * Categorize this predicate. Initially, this means
498      * building a bit map of the referenced tables for each predicate.
499      * If the source of this ColumnReference (at the next underlying level)
500      * is not a ColumnReference or a VirtualColumnNode then this predicate
501      * will not be pushed down.
502      *
503      * For example, in:
504      * select * from (select 1 from s) a (x) where x = 1
505      * we will not push down x = 1.
506      * NOTE: It would be easy to handle the case of a constant, but if the
507      * inner SELECT returns an arbitrary expression, then we would have to copy
508      * that tree into the pushed predicate, and that tree could contain
509      * subqueries and method calls.
510      * RESOLVE - revisit this issue once we have views.
511      *
512      * @param referencedTabs JBitSet with bit map of referenced FromTables
513      * @param simplePredsOnly Whether or not to consider method
514      * calls, field references and conditional nodes
515      * when building bit map
516      *
517      * @return boolean Whether or not source.expression is a ColumnReference
518      * or a VirtualColumnNode.
519      *
520      * @exception StandardException Thrown on error
521      */

522     public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)
523         throws StandardException
524     {
525         return (operand == null) ?
526                 false :
527                 operand.categorize(referencedTabs, simplePredsOnly);
528     }
529
530     /**
531      * Remap all ColumnReferences in this tree to be clones of the
532      * underlying expression.
533      *
534      * @return ValueNode The remapped expression tree.
535      *
536      * @exception StandardException Thrown on error
537      */

538     public ValueNode remapColumnReferencesToExpressions()
539         throws StandardException
540     {
541         if (operand != null)
542         {
543             operand = operand.remapColumnReferencesToExpressions();
544         }
545         return this;
546     }
547
548     /**
549      * Return whether or not this expression tree represents a constant expression.
550      *
551      * @return Whether or not this expression tree represents a constant expression.
552      */

553     public boolean isConstantExpression()
554     {
555         return (operand == null) ? true: operand.isConstantExpression();
556     }
557
558     /** @see ValueNode#constantExpression */
559     public boolean constantExpression(PredicateList whereClause)
560     {
561         return (operand == null) ?
562                     true :
563                     operand.constantExpression(whereClause);
564     }
565
566     /**
567      * @see ValueNode#requiresTypeFromContext
568      */

569     public boolean requiresTypeFromContext()
570     {
571         if (operand == null)
572             return false;
573         else
574             return (operand.requiresTypeFromContext());
575     }
576
577
578     /**
579      * Returns true if this UnaryOperatorNode is for -?/+?.
580      * This is required to check -?/+? say in the following sql
581      * select * from t1 where -? and c11=c11 or +?
582      *
583      * @return True if this +?/-? node
584      */

585     public boolean isUnaryMinusOrPlusWithParameter()
586     {
587         if (operand !=null && operand instanceof ParameterNode && operand.requiresTypeFromContext() &&
588                 (operator!= null && (operator.equals("-") || operator.equals("+"))))
589             return true;
590         else
591             return false;
592     }
593
594     /**
595      * By default unary operators don't accept ? parameters as operands.
596      * This can be over-ridden for particular unary operators.
597      *
598      * We throw an exception if the parameter doesn't have a datatype
599      * assigned to it yet.
600      *
601      * @exception StandardException Thrown if ? parameter doesn't
602      * have a type bound to it yet.
603      * ? parameter where it isn't allowed.
604      */

605
606     void bindParameter() throws StandardException
607     {
608         if (operatorType == XMLPARSE_OP)
609         {
610             /* SQL/XML[2006] allows both binary and character strings for
611              * the XMLParse parameter (section 10.16:Function). The spec
612              * also goes on to say, in section 6.15:Conformance Rules:4,
613              * that:
614              *
615              * "Without Feature X066, XMLParse: BLOB input and DOCUMENT
616              * option, in conforming SQL language, the declared type of
617              * the <string value expression> immediately contained in
618              * <XML parse> shall not be a binary string type."
619              *
620              * Thus since Derby doesn't currently support BLOB input,
621              * we have to ensure that the "declared type" of the parameter
622              * is not a binary string type; i.e. it must be a character
623              * string type. Since there's no way to determine what the
624              * declared type is from the XMLPARSE syntax, the user must
625              * explicitly declare the type of the parameter, and it must
626              * be a character string. They way s/he does that is by
627              * specifying an explicit CAST on the parameter, such as:
628              *
629              * insert into myXmlTable (xcol) values
630              * XMLPARSE(DOCUMENT cast (? as CLOB) PRESERVE WHITESPACE);
631              *
632              * If that was done then we wouldn't be here; we only get
633              * here if the parameter was specified without a cast. That
634              * means we don't know what the "declared type" is and so
635              * we throw an error.
636              */

637             throw StandardException.newException(
638                 SQLState.LANG_XMLPARSE_UNKNOWN_PARAM_TYPE);
639         }
640         else if (operatorType == XMLSERIALIZE_OP) {
641         // For now, since JDBC has no type defined for XML, we
642
// don't allow binding to an XML parameter.
643
throw StandardException.newException(
644                SQLState.LANG_ATTEMPT_TO_BIND_XML);
645         }
646         else if (operand.getTypeServices() == null)
647         {
648             throw StandardException.newException(SQLState.LANG_UNARY_OPERAND_PARM, operator);
649         }
650     }
651
652     /**
653      * Do code generation for this unary operator.
654      *
655      * @param acb The ExpressionClassBuilder for the class we're generating
656      * @param mb The method the expression will go into
657      *
658      *
659      * @exception StandardException Thrown on error
660      */

661
662     public void generateExpression(ExpressionClassBuilder acb,
663                                             MethodBuilder mb)
664                                     throws StandardException
665     {
666         if (operand == null)
667             return;
668
669         // For XML operator we do some extra work.
670
boolean xmlGen = (operatorType == XMLPARSE_OP) ||
671             (operatorType == XMLSERIALIZE_OP);
672
673         if (xmlGen) {
674         // We create an execution-time object from which we call
675
// the necessary methods. We do this for two reasons: 1) this
676
// level of indirection allows us to separate the XML data type
677
// from the required XML implementation classes (esp. JAXP and
678
// Xalan classes)--for more on how this works, see the comments
679
// in SqlXmlUtil.java; and 2) this allows us to create the
680
// required XML objects a single time (which we did at bind time
681
// when we created a new SqlXmlUtil) and then reuse those objects
682
// for each row in the target result set, instead of creating
683
// new objects every time; see SqlXmlUtil.java for more.
684
mb.pushNewStart(
685                 "org.apache.derby.impl.sql.execute.SqlXmlExecutor");
686             mb.pushNewComplete(addXmlOpMethodParams(acb, mb));
687         }
688
689         String JavaDoc resultTypeName =
690             (operatorType == -1)
691                 ? getTypeCompiler().interfaceName()
692                 : resultInterfaceType;
693             
694         // System.out.println("resultTypeName " + resultTypeName + " method " + methodName);
695
// System.out.println("isBooleanTypeId() " + getTypeId().isBooleanTypeId());
696

697         boolean needField = !getTypeId().isBooleanTypeId();
698
699         String JavaDoc receiverType = getReceiverInterfaceName();
700         operand.generateExpression(acb, mb);
701         mb.cast(receiverType);
702
703         if (needField) {
704
705             /* Allocate an object for re-use to hold the result of the operator */
706             LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);
707             mb.getField(field);
708
709             /* If we're calling a method on a class (SqlXmlExecutor) instead
710              * of calling a method on the operand interface, then we invoke
711              * VIRTUAL; we then have 2 args (the operand and the local field)
712              * instead of one, i.e:
713              *
714              * SqlXmlExecutor.method(operand, field)
715              *
716              * instead of
717              *
718              * <operand>.method(field).
719              */

720             if (xmlGen) {
721                 mb.callMethod(VMOpcode.INVOKEVIRTUAL, null,
722                     methodName, resultTypeName, 2);
723             }
724             else {
725                 mb.callMethod(VMOpcode.INVOKEINTERFACE,
726                     (String JavaDoc) null, methodName, resultTypeName, 1);
727             }
728
729             /*
730             ** Store the result of the method call in the field, so we can re-use
731             ** the object.
732             */

733             mb.putField(field);
734         } else {
735             mb.callMethod(VMOpcode.INVOKEINTERFACE, (String JavaDoc) null,
736                 methodName, resultTypeName, 0);
737         }
738     }
739
740     /**
741      * Determine the type the binary method is called on.
742      * By default, based on the receiver.
743      *
744      * Override in nodes that use methods on super-interfaces of
745      * the receiver's interface, such as comparisons.
746      *
747      * @exception StandardException Thrown on error
748      */

749     public String JavaDoc getReceiverInterfaceName() throws StandardException {
750         if (SanityManager.DEBUG)
751         {
752             SanityManager.ASSERT(operand!=null,
753                                 "cannot get interface without operand");
754         }
755
756         if (operatorType != -1)
757             return receiverInterfaceType;
758         
759         return operand.getTypeCompiler().interfaceName();
760     }
761
762     /**
763      * Return the variant type for the underlying expression.
764      * The variant type can be:
765      * VARIANT - variant within a scan
766      * (method calls and non-static field access)
767      * SCAN_INVARIANT - invariant within a scan
768      * (column references from outer tables)
769      * QUERY_INVARIANT - invariant within the life of a query
770      * (constant expressions)
771      * CONSTANT - immutable
772      *
773      * @return The variant type for the underlying expression.
774      * @exception StandardException thrown on error
775      */

776     protected int getOrderableVariantType() throws StandardException
777     {
778         /*
779         ** If we have nothing in the operator, then
780         ** it must be constant.
781         */

782         return (operand != null) ?
783                 operand.getOrderableVariantType() :
784                 Qualifier.CONSTANT;
785     }
786
787     /**
788      * Accept a visitor, and call v.visit()
789      * on child nodes as necessary.
790      *
791      * @param v the visitor
792      *
793      * @exception StandardException on error
794      */

795     public Visitable accept(Visitor v)
796         throws StandardException
797     {
798         Visitable returnNode = v.visit(this);
799
800         if (v.skipChildren(this))
801         {
802             return returnNode;
803         }
804
805         if (operand != null && !v.stopTraversal())
806         {
807             operand = (ValueNode)operand.accept(v);
808         }
809
810         return returnNode;
811     }
812
813     /**
814      * Add some additional arguments to our method call for
815      * XML related operations like XMLPARSE and XMLSERIALIZE.
816      * @param mb The MethodBuilder that will make the call.
817      * @return Number of parameters added.
818      */

819     protected int addXmlOpMethodParams(ExpressionClassBuilder acb,
820         MethodBuilder mb) throws StandardException
821     {
822         if ((operatorType != XMLPARSE_OP) && (operatorType != XMLSERIALIZE_OP))
823         // nothing to do.
824
return 0;
825
826         if (operatorType == XMLSERIALIZE_OP) {
827         // We push the target type's JDBC type id as well as
828
// the maximum width, since both are required when
829
// we actually perform the operation, and both are
830
// primitive types. Note: we don't have to save
831
// any objects for XMLSERIALIZE because it doesn't
832
// require any XML-specific objects: it just returns
833
// the serialized version of the XML value, which we
834
// already found when the XML value was created (ex.
835
// as part of the XMLPARSE work).
836
DataTypeDescriptor targetType =
837                 (DataTypeDescriptor)additionalArgs[0];
838             mb.push(targetType.getJDBCTypeId());
839             mb.push(targetType.getMaximumWidth());
840             return 2;
841         }
842
843         /* Else we're here for XMLPARSE. */
844
845         // Push activation, which we use at execution time to
846
// get our saved object (which will hold objects used
847
// for parsing/serializing) back.
848
acb.pushThisAsActivation(mb);
849
850         // Push our XML object (used for parsing/serializing) as
851
// a saved object, so that we can retrieve it at execution
852
// time. This allows us to avoid having to re-create the
853
// objects for every row in a given result set.
854
mb.push(getCompilerContext().addSavedObject(sqlxUtil));
855
856         // Push whether or not we want to preserve whitespace.
857
mb.push(((Boolean JavaDoc)additionalArgs[0]).booleanValue());
858         return 3;
859     }
860     
861     /**
862      * @throws StandardException
863      * {@inheritDoc}
864      */

865     protected boolean isEquivalent(ValueNode o) throws StandardException
866     {
867         if (isSameNodeType(o))
868         {
869         // the first condition in the || covers the case when
870
// both operands are null.
871
UnaryOperatorNode other = (UnaryOperatorNode)o;
872             return (operator.equals(other.operator) &&
873             ((operand == other.operand)||
874              ((operand != null) && operand.isEquivalent(other.operand))));
875         }
876         return false;
877     }
878 }
879
Popular Tags