KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.ConditionalNode
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.services.compiler.MethodBuilder;
25
26 import org.apache.derby.iapi.services.monitor.Monitor;
27
28 import org.apache.derby.iapi.services.sanity.SanityManager;
29
30 import org.apache.derby.iapi.error.StandardException;
31
32 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
33
34 import org.apache.derby.iapi.types.TypeId;
35
36 import org.apache.derby.iapi.types.BooleanDataValue;
37 import org.apache.derby.iapi.types.DataTypeDescriptor;
38 import org.apache.derby.iapi.types.DataValueFactory;
39
40 import org.apache.derby.iapi.reference.SQLState;
41
42 import org.apache.derby.iapi.types.DataValueDescriptor;
43 import org.apache.derby.iapi.types.TypeId;
44
45 import org.apache.derby.iapi.services.loader.ClassInspector;
46
47 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
48
49 import org.apache.derby.iapi.sql.compile.Visitable;
50 import org.apache.derby.iapi.sql.compile.Visitor;
51 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
52 import org.apache.derby.iapi.reference.ClassName;
53
54
55 import org.apache.derby.iapi.util.JBitSet;
56 import org.apache.derby.iapi.services.classfile.VMOpcode;
57
58 import java.util.Vector JavaDoc;
59
60 /**
61  * A ConditionalNode represents an if/then/else operator with a single
62  * boolean expression on the "left" of the operator and a list of expressions on
63  * the "right". This is used to represent the java conditional (aka immediate if).
64  *
65  * @author Jerry Brenner
66  */

67
68 public class ConditionalNode extends ValueNode
69 {
70     ValueNode testCondition;
71     ValueNodeList thenElseList;
72     //true means we are here for NULLIF(V1,V2), false means we are here for following
73
//CASE WHEN BooleanExpression THEN thenExpression ELSE elseExpression END
74
boolean thisIsNullIfNode;
75
76     /**
77      * Initializer for a ConditionalNode
78      *
79      * @param testCondition The boolean test condition
80      * @param thenElseList ValueNodeList with then and else expressions
81      */

82
83     public void init(Object JavaDoc testCondition, Object JavaDoc thenElseList, Object JavaDoc thisIsNullIfNode)
84     {
85         this.testCondition = (ValueNode) testCondition;
86         this.thenElseList = (ValueNodeList) thenElseList;
87         this.thisIsNullIfNode = ((Boolean JavaDoc) thisIsNullIfNode).booleanValue();
88     }
89
90     /**
91      * Prints the sub-nodes of this object. See QueryTreeNode.java for
92      * how tree printing is supposed to work.
93      *
94      * @param depth The depth of this node in the tree
95      */

96
97     public void printSubNodes(int depth)
98     {
99         if (SanityManager.DEBUG)
100         {
101             super.printSubNodes(depth);
102
103             if (testCondition != null)
104             {
105                 printLabel(depth, "testCondition: ");
106                 testCondition.treePrint(depth + 1);
107             }
108
109             if (thenElseList != null)
110             {
111                 printLabel(depth, "thenElseList: ");
112                 thenElseList.treePrint(depth + 1);
113             }
114         }
115     }
116
117     /**
118      * Set the clause that this node appears in.
119      *
120      * @param clause The clause that this node appears in.
121      */

122     public void setClause(int clause)
123     {
124         super.setClause(clause);
125         testCondition.setClause(clause);
126         thenElseList.setClause(clause);
127     }
128
129     /**
130      * Bind this expression. This means binding the sub-expressions,
131      * as well as figuring out what the return type is for this expression.
132      *
133      * @param fromList The FROM list for the query this
134      * expression is in, for binding columns.
135      * @param subqueryList The subquery list being built as we find SubqueryNodes
136      * @param aggregateVector The aggregate vector being built as we find AggregateNodes
137      *
138      * @return The new top of the expression tree.
139      *
140      * @exception StandardException Thrown on error
141      */

142
143     public ValueNode bindExpression(FromList fromList, SubqueryList subqueryList,
144         Vector JavaDoc aggregateVector)
145             throws StandardException
146     {
147         testCondition = testCondition.bindExpression(fromList,
148             subqueryList,
149             aggregateVector);
150
151         if (thisIsNullIfNode) {
152             //for NULLIF(V1,V2), parser binds thenElseList.elementAt(0) to untyped NULL
153
//At bind phase, we should bind it to the type of V1 since now we know the
154
//type of V1
155
BinaryComparisonOperatorNode bcon = (BinaryComparisonOperatorNode)testCondition;
156             
157             /*
158              * NULLIF(V1,V2) is equivalent to:
159              *
160              * CASE WHEN V1=V2 THEN NULL ELSE V1 END
161              *
162              * The untyped NULL should have a data type descriptor
163              * that allows its value to be nullable.
164              */

165             QueryTreeNode cast = getNodeFactory().getNode(
166                         C_NodeTypes.CAST_NODE,
167                         thenElseList.elementAt(0),
168                         new DataTypeDescriptor(
169                                 bcon.getLeftOperand().getTypeServices(), true),
170                         getContextManager());
171             thenElseList.setElementAt(cast,0);
172         }
173         thenElseList.bindExpression(fromList,
174             subqueryList,
175             aggregateVector);
176
177         // Can't get the then and else expressions until after they've been bound
178
ValueNode thenExpression = (ValueNode) thenElseList.elementAt(0);
179         ValueNode elseExpression = (ValueNode) thenElseList.elementAt(1);
180
181         /* testCondition must be a boolean expression.
182          * If it is a ? parameter on the left, then set type to boolean,
183          * otherwise verify that the result type is boolean.
184          */

185         if (testCondition.requiresTypeFromContext())
186         {
187             testCondition.setType(
188                             new DataTypeDescriptor(
189                                         TypeId.BOOLEAN_ID,
190                                         true));
191         }
192         else
193         {
194             if ( ! testCondition.getTypeServices().getTypeId().equals(
195                                                         TypeId.BOOLEAN_ID))
196             {
197                 throw StandardException.newException(SQLState.LANG_CONDITIONAL_NON_BOOLEAN);
198             }
199         }
200
201         /* We can't determine the type for the result expression if
202          * all result expressions are ?s.
203          */

204         if (thenElseList.containsAllParameterNodes())
205         {
206             throw StandardException.newException(SQLState.LANG_ALL_RESULT_EXPRESSIONS_PARAMS, "conditional");
207         }
208         else if (thenElseList.containsParameterNode())
209         {
210             /* Set the parameter's type to be the same as the other element in
211              * the list
212              */

213
214             DataTypeDescriptor dts;
215             ValueNode typeExpression;
216
217             if (thenExpression.requiresTypeFromContext())
218             {
219                 dts = elseExpression.getTypeServices();
220             }
221             else
222             {
223                 dts = thenExpression.getTypeServices();
224             }
225
226             thenElseList.setParameterDescriptor(dts);
227         }
228
229         /* The then and else expressions must be type compatible */
230         ClassInspector cu = getClassFactory().getClassInspector();
231
232         /*
233         ** If it is comparable, then we are ok. Note that we
234         ** could in fact allow any expressions that are convertible()
235         ** since we are going to generate a cast node, but that might
236         ** be confusing to users...
237         */

238
239         // RESOLVE DJDOI - this looks wrong, why should the then expression
240
// be comparable to the then expression ??
241
if (! thenExpression.getTypeCompiler().
242              comparable(elseExpression.getTypeId(), false, getClassFactory()) &&
243             ! cu.assignableTo(thenExpression.getTypeId().getCorrespondingJavaTypeName(),
244                               elseExpression.getTypeId().getCorrespondingJavaTypeName()) &&
245             ! cu.assignableTo(elseExpression.getTypeId().getCorrespondingJavaTypeName(),
246                               thenExpression.getTypeId().getCorrespondingJavaTypeName()))
247         {
248             throw StandardException.newException(SQLState.LANG_NOT_TYPE_COMPATIBLE,
249                         thenExpression.getTypeId().getSQLTypeName(),
250                         elseExpression.getTypeId().getSQLTypeName()
251                         );
252         }
253
254         /*
255         ** Set the result type of this conditional to be the dominant type
256         ** of the result expressions.
257         */

258         setType(thenElseList.getDominantTypeServices());
259
260         /*
261         ** Generate a CastNode if necessary and
262         ** stick it over the original expression
263         */

264         TypeId condTypeId = getTypeId();
265         TypeId thenTypeId = ((ValueNode) thenElseList.elementAt(0)).getTypeId();
266         TypeId elseTypeId = ((ValueNode) thenElseList.elementAt(1)).getTypeId();
267
268         /* Need to generate conversion if thenExpr or elseExpr is not of
269          * dominant type. (At least 1 of them must be of the dominant type.)
270          */

271         if (thenTypeId.typePrecedence() != condTypeId.typePrecedence())
272         {
273             ValueNode cast = (ValueNode) getNodeFactory().getNode(
274                                 C_NodeTypes.CAST_NODE,
275                                 thenElseList.elementAt(0),
276                                 dataTypeServices, // cast to dominant type
277
getContextManager());
278             cast = cast.bindExpression(fromList,
279                                             subqueryList,
280                                             aggregateVector);
281             
282             thenElseList.setElementAt(cast, 0);
283         }
284
285         else if (elseTypeId.typePrecedence() != condTypeId.typePrecedence())
286         {
287             ValueNode cast = (ValueNode) getNodeFactory().getNode(
288                                 C_NodeTypes.CAST_NODE,
289                                 thenElseList.elementAt(1),
290                                 dataTypeServices, // cast to dominant type
291
getContextManager());
292             cast = cast.bindExpression(fromList,
293                                             subqueryList,
294                                             aggregateVector);
295             
296             thenElseList.setElementAt(cast, 1);
297         }
298
299         return this;
300     }
301
302     /**
303      * Preprocess an expression tree. We do a number of transformations
304      * here (including subqueries, IN lists, LIKE and BETWEEN) plus
305      * subquery flattening.
306      * NOTE: This is done before the outer ResultSetNode is preprocessed.
307      *
308      * @param numTables Number of tables in the DML Statement
309      * @param outerFromList FromList from outer query block
310      * @param outerSubqueryList SubqueryList from outer query block
311      * @param outerPredicateList PredicateList from outer query block
312      *
313      * @return The modified expression
314      *
315      * @exception StandardException Thrown on error
316      */

317     public ValueNode preprocess(int numTables,
318                                 FromList outerFromList,
319                                 SubqueryList outerSubqueryList,
320                                 PredicateList outerPredicateList)
321                     throws StandardException
322     {
323         testCondition = testCondition.preprocess(numTables,
324                                                  outerFromList, outerSubqueryList,
325                                                  outerPredicateList);
326         thenElseList.preprocess(numTables,
327                                 outerFromList, outerSubqueryList,
328                                 outerPredicateList);
329         return this;
330     }
331
332     /**
333      * Categorize this predicate. Initially, this means
334      * building a bit map of the referenced tables for each predicate.
335      * If the source of this ColumnReference (at the next underlying level)
336      * is not a ColumnReference or a VirtualColumnNode then this predicate
337      * will not be pushed down.
338      *
339      * For example, in:
340      * select * from (select 1 from s) a (x) where x = 1
341      * we will not push down x = 1.
342      * NOTE: It would be easy to handle the case of a constant, but if the
343      * inner SELECT returns an arbitrary expression, then we would have to copy
344      * that tree into the pushed predicate, and that tree could contain
345      * subqueries and method calls.
346      * RESOLVE - revisit this issue once we have views.
347      *
348      * @param referencedTabs JBitSet with bit map of referenced FromTables
349      * @param simplePredsOnly Whether or not to consider method
350      * calls, field references and conditional nodes
351      * when building bit map
352      *
353      * @return boolean Whether or not source.expression is a ColumnReference
354      * or a VirtualColumnNode.
355      * @exception StandardException Thrown on error
356      */

357     public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)
358         throws StandardException
359     {
360         /* We stop here when only considering simple predicates
361          * as we don't consider conditional operators when looking
362          * for null invariant predicates.
363          */

364         if (simplePredsOnly)
365         {
366             return false;
367         }
368
369         boolean pushable;
370
371         pushable = testCondition.categorize(referencedTabs, simplePredsOnly);
372         pushable = (thenElseList.categorize(referencedTabs, simplePredsOnly) && pushable);
373         return pushable;
374     }
375
376     /**
377      * Remap all ColumnReferences in this tree to be clones of the
378      * underlying expression.
379      *
380      * @return ValueNode The remapped expression tree.
381      *
382      * @exception StandardException Thrown on error
383      */

384     public ValueNode remapColumnReferencesToExpressions()
385         throws StandardException
386     {
387         testCondition = testCondition.remapColumnReferencesToExpressions();
388         thenElseList = thenElseList.remapColumnReferencesToExpressions();
389         return this;
390     }
391
392     /**
393      * Return whether or not this expression tree represents a constant expression.
394      *
395      * @return Whether or not this expression tree represents a constant expression.
396      */

397     public boolean isConstantExpression()
398     {
399         return (testCondition.isConstantExpression() &&
400                 thenElseList.isConstantExpression());
401     }
402
403     /** @see ValueNode#constantExpression */
404     public boolean constantExpression(PredicateList whereClause)
405     {
406         return (testCondition.constantExpression(whereClause) &&
407                 thenElseList.constantExpression(whereClause));
408     }
409
410     /**
411      * Eliminate NotNodes in the current query block. We traverse the tree,
412      * inverting ANDs and ORs and eliminating NOTs as we go. We stop at
413      * ComparisonOperators and boolean expressions. We invert
414      * ComparisonOperators and replace boolean expressions with
415      * boolean expression = false.
416      * NOTE: Since we do not recurse under ComparisonOperators, there
417      * still could be NotNodes left in the tree.
418      *
419      * @param underNotNode Whether or not we are under a NotNode.
420      *
421      *
422      * @return The modified expression
423      *
424      * @exception StandardException Thrown on error
425      */

426     ValueNode eliminateNots(boolean underNotNode)
427                     throws StandardException
428     {
429         ValueNode thenExpression;
430         ValueNode elseExpression;
431
432         if (! underNotNode)
433         {
434             return this;
435         }
436
437         /* Simply swap the then and else expressions */
438         thenExpression = (ValueNode) thenElseList.elementAt(0);
439         elseExpression = (ValueNode) thenElseList.elementAt(1);
440         thenElseList.setElementAt(elseExpression, 0);
441         thenElseList.setElementAt(thenExpression, 1);
442
443         return this;
444     }
445
446     /**
447      * Do code generation for this conditional expression.
448      *
449      * @param acb The ExpressionClassBuilder for the class we're generating
450      * @param mb The method the expression will go into
451      *
452      * @exception StandardException Thrown on error
453      */

454
455     public void generateExpression(ExpressionClassBuilder acb,
456                                             MethodBuilder mb)
457                                     throws StandardException
458     {
459         testCondition.generateExpression(acb, mb);
460         mb.cast(ClassName.BooleanDataValue);
461         mb.push(true);
462         mb.callMethod(VMOpcode.INVOKEINTERFACE, (String JavaDoc) null, "equals", "boolean", 1);
463
464         mb.conditionalIf();
465           ((ValueNode) thenElseList.elementAt(0)).generateExpression(acb, mb);
466         mb.startElseCode();
467           ((ValueNode) thenElseList.elementAt(1)).generateExpression(acb, mb);
468         mb.completeConditional();
469     }
470
471     /**
472      * Accept a visitor, and call v.visit()
473      * on child nodes as necessary.
474      *
475      * @param v the visitor
476      *
477      * @exception StandardException on error
478      */

479     public Visitable accept(Visitor v)
480         throws StandardException
481     {
482         Visitable returnNode = v.visit(this);
483     
484         if (v.skipChildren(this))
485         {
486             return returnNode;
487         }
488
489         if (testCondition != null && !v.stopTraversal())
490         {
491             testCondition = (ValueNode)testCondition.accept(v);
492         }
493
494         if (thenElseList != null && !v.stopTraversal())
495         {
496             thenElseList = (ValueNodeList)thenElseList.accept(v);
497         }
498         
499         return returnNode;
500     }
501         
502     /**
503      * {@inheritDoc}
504      */

505     protected boolean isEquivalent(ValueNode o) throws StandardException
506     {
507         if (isSameNodeType(o))
508         {
509             ConditionalNode other = (ConditionalNode)o;
510             if (thenElseList.size() == other.thenElseList.size()
511                     && (testCondition.isEquivalent(other.testCondition)))
512             {
513                 int sz = thenElseList.size();
514                 for (int i = 0; i < sz; i++)
515                 {
516                     ValueNode v1 = (ValueNode)thenElseList.elementAt(i);
517                     ValueNode v2 = (ValueNode)other.thenElseList.elementAt(i);
518                     if (!v1.isEquivalent(v2))
519                     {
520                         return false;
521                     }
522                     
523                 }
524                 return true;
525             }
526         }
527         return false;
528     }
529 }
530
Popular Tags