KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.BinaryComparisonOperatorNode
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.C_NodeTypes;
25 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
26
27 import org.apache.derby.iapi.sql.compile.TypeCompiler;
28 import org.apache.derby.iapi.types.DataValueDescriptor;
29 import org.apache.derby.iapi.types.TypeId;
30 import org.apache.derby.iapi.types.DataTypeDescriptor;
31
32 import org.apache.derby.iapi.reference.SQLState;
33 import org.apache.derby.iapi.reference.ClassName;
34 import org.apache.derby.iapi.error.StandardException;
35
36 import org.apache.derby.iapi.services.sanity.SanityManager;
37
38 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
39
40 import java.util.Vector JavaDoc;
41 import java.sql.Types JavaDoc;
42
43 /**
44  * This node is the superclass for all binary comparison operators, such as =,
45  * <>, <, etc.
46  *
47  * @author Jeff Lichtman
48  */

49
50 public abstract class BinaryComparisonOperatorNode extends BinaryOperatorNode
51 {
52     // Use between selectivity?
53
private boolean forQueryRewrite;
54     private boolean betweenSelectivity;
55
56     /**
57      * Initializer for a BinaryComparisonOperatorNode
58      *
59      * @param leftOperand The left operand of the comparison
60      * @param rightOperand The right operand of the comparison
61      * @param operator The name of the operator
62      * @param methodName The name of the method to call in the generated
63      * class
64      */

65
66     public void init(
67                 Object JavaDoc leftOperand,
68                 Object JavaDoc rightOperand,
69                 Object JavaDoc operator,
70                 Object JavaDoc methodName)
71     {
72         super.init(leftOperand, rightOperand, operator, methodName,
73                 ClassName.DataValueDescriptor, ClassName.DataValueDescriptor);
74     }
75
76     /**
77      * This node was generated as part of a query rewrite. Bypass the
78      * normal comparability checks.
79      * @param val true if this was for a query rewrite
80      */

81     public void setForQueryRewrite(boolean val)
82     {
83         forQueryRewrite=val;
84     }
85
86     /**
87      * Was this node generated in a query rewrite?
88      *
89      * @return true if it was generated in a query rewrite.
90      */

91     public boolean getForQueryRewrite()
92     {
93         return forQueryRewrite;
94     }
95
96     /**
97      * Use between selectivity when calculating the selectivity.
98      */

99     void setBetweenSelectivity()
100     {
101         betweenSelectivity = true;
102     }
103
104     /**
105      * Return whether or not to use the between selectivity for this node.
106      *
107      * @return Whether or not to use the between selectivity for this node.
108      */

109     boolean getBetweenSelectivity()
110     {
111         return betweenSelectivity;
112     }
113
114
115     /**
116      * Bind this comparison operator. All that has to be done for binding
117      * a comparison operator is to bind the operands, check the compatibility
118      * of the types, and set the result type to SQLBoolean.
119      *
120      * @param fromList The query's FROM list
121      * @param subqueryList The subquery list being built as we find SubqueryNodes
122      * @param aggregateVector The aggregate vector being built as we find AggregateNodes
123      *
124      * @return The new top of the expression tree.
125      *
126      * @exception StandardException Thrown on error
127      */

128
129     public ValueNode bindExpression(
130         FromList fromList, SubqueryList subqueryList,
131         Vector JavaDoc aggregateVector)
132             throws StandardException
133     {
134         super.bindExpression(fromList, subqueryList, aggregateVector);
135
136 //RESOLVELOCALIZE - convert constants to national constants
137
TypeCompiler leftTC = leftOperand.getTypeCompiler();
138         TypeCompiler rightTC = rightOperand.getTypeCompiler();
139         TypeId leftTypeId = leftOperand.getTypeId();
140         TypeId rightTypeId = rightOperand.getTypeId();
141
142         /*
143          * If we are comparing a non-string with a string type, then we
144          * must prevent the non-string value from being used to probe into
145          * an index on a string column. This is because the string types
146          * are all of low precedence, so the comparison rules of the non-string
147          * value are used, so it may not find values in a string index because
148          * it will be in the wrong order. So, cast the string value to its
149          * own type. This is easier than casting it to the non-string type,
150          * because we would have to figure out the right length to cast it to.
151          */

152         if (! leftTypeId.isStringTypeId() && rightTypeId.isStringTypeId())
153         {
154             DataTypeDescriptor rightTypeServices = rightOperand.getTypeServices();
155
156             rightOperand = (ValueNode)
157                 getNodeFactory().getNode(
158                     C_NodeTypes.CAST_NODE,
159                     rightOperand,
160                     new DataTypeDescriptor(
161                             rightTypeId,
162                             true,
163                             rightTypeServices.getMaximumWidth()),
164                     getContextManager());
165             ((CastNode) rightOperand).bindCastNodeOnly();
166         }
167         else if (! rightTypeId.isStringTypeId() && leftTypeId.isStringTypeId())
168         {
169             DataTypeDescriptor leftTypeServices = leftOperand.getTypeServices();
170
171             leftOperand = (ValueNode)
172                 getNodeFactory().getNode(
173                     C_NodeTypes.CAST_NODE,
174                     leftOperand,
175                     new DataTypeDescriptor(
176                             leftTypeId,
177                             true,
178                             leftTypeServices.getMaximumWidth()),
179                     getContextManager());
180             ((CastNode) leftOperand).bindCastNodeOnly();
181         }
182         /* If we are comparing a char with a national char then
183          * we need to generate a cast to the appropriate national
184          * char above the char operand.
185          */

186         else if (! leftTypeId.isNationalStringTypeId() &&
187             rightTypeId.isNationalStringTypeId())
188         {
189             leftOperand = (ValueNode)
190                 getNodeFactory().getNode(
191                     C_NodeTypes.CAST_NODE,
192                     leftOperand,
193                     DataTypeDescriptor.getBuiltInDataTypeDescriptor(leftTC.getMatchingNationalCharTypeName(),
194                                         leftTC.getCastToCharWidth(
195                                             leftOperand.getTypeServices())),
196                     getContextManager());
197             ((CastNode) leftOperand).bindCastNodeOnly();
198         }
199         else if (! rightTypeId.isNationalStringTypeId() &&
200                 leftTypeId.isNationalStringTypeId())
201         {
202             rightOperand = (ValueNode)
203                 getNodeFactory().getNode(
204                     C_NodeTypes.CAST_NODE,
205                     rightOperand,
206                     DataTypeDescriptor.getBuiltInDataTypeDescriptor(rightTC.getMatchingNationalCharTypeName(),
207                                         rightTC.getCastToCharWidth(
208                                             rightOperand.getTypeServices())),
209                     getContextManager());
210             ((CastNode) rightOperand).bindCastNodeOnly();
211         }
212
213         /* Test type compatability and set type info for this node */
214         bindComparisonOperator();
215
216         return this;
217     }
218
219
220     /**
221      * Test the type compatability of the operands and set the type info
222      * for this node. This method is useful both during binding and
223      * when we generate nodes within the language module outside of the parser.
224      *
225      * @exception StandardException Thrown on error
226      */

227     public void bindComparisonOperator()
228             throws StandardException
229     {
230         TypeId leftType;
231         TypeId rightType;
232         boolean nullableResult;
233
234         leftType = leftOperand.getTypeId();
235         rightType = rightOperand.getTypeId();
236
237
238         /*
239         ** Can the types be compared to each other? If not, throw an
240         ** exception.
241         */

242         boolean forEquals = operator.equals("=") || operator.equals("<>");
243
244         boolean cmp = leftOperand.getTypeCompiler().comparable(rightType,
245                                                                forEquals,
246                                                                getClassFactory());
247         // Bypass the comparable check if this is a rewrite from the
248
// optimizer. We will assume Mr. Optimizer knows what he is doing.
249
if (!cmp && !forQueryRewrite) {
250             throw StandardException.newException(SQLState.LANG_NOT_COMPARABLE,
251                     leftType.getSQLTypeName(),
252                     rightType.getSQLTypeName()
253                 );
254           }
255
256         
257         /*
258         ** Set the result type of this comparison operator based on the
259         ** operands. The result type is always SQLBoolean - the only question
260         ** is whether it is nullable or not. If either of the operands is
261         ** nullable, the result of the comparison must be nullable, too, so
262         ** we can represent the unknown truth value.
263         */

264         nullableResult = leftOperand.getTypeServices().isNullable() ||
265                             rightOperand.getTypeServices().isNullable();
266         setType(new DataTypeDescriptor(TypeId.BOOLEAN_ID, nullableResult));
267
268
269     }
270
271     /**
272      * Preprocess an expression tree. We do a number of transformations
273      * here (including subqueries, IN lists, LIKE and BETWEEN) plus
274      * subquery flattening.
275      * NOTE: This is done before the outer ResultSetNode is preprocessed.
276      *
277      * @param numTables Number of tables in the DML Statement
278      * @param outerFromList FromList from outer query block
279      * @param outerSubqueryList SubqueryList from outer query block
280      * @param outerPredicateList PredicateList from outer query block
281      *
282      * @return The modified expression
283      *
284      * @exception StandardException Thrown on error
285      */

286     public ValueNode preprocess(int numTables,
287                                 FromList outerFromList,
288                                 SubqueryList outerSubqueryList,
289                                 PredicateList outerPredicateList)
290                     throws StandardException
291     {
292         leftOperand = leftOperand.preprocess(numTables,
293                                              outerFromList, outerSubqueryList,
294                                              outerPredicateList);
295
296         /* This is where we start to consider flattening expression subqueries based
297          * on a uniqueness condition. If the right child is a SubqueryNode then
298          * it is a potentially flattenable expression subquery. If we flatten the
299          * subquery then we at least need to change the right operand of this
300          * comparison. However, we may want to push the comparison into the subquery
301          * itself and replace this outer comparison with TRUE in the tree. Thus we
302          * return rightOperand.preprocess() if the rightOperand is a SubqueryNode.
303          * NOTE: SubqueryNode.preprocess() is smart enough to return this node
304          * if it is not flattenable.
305          * NOTE: We only do this if the subquery has not yet been preprocessed.
306          * (A subquery can get preprocessed multiple times if it is a child node
307          * in an expression that gets transformed, like BETWEEN. The subquery
308          * remembers whether or not it has been preprocessed and simply returns if
309          * it has already been preprocessed. The return returns the SubqueryNode,
310          * so an invalid tree is returned if we set the parent comparison operator
311          * when the subquery has already been preprocessed.)
312          */

313         if ((rightOperand instanceof SubqueryNode) &&
314             !((SubqueryNode) rightOperand).getPreprocessed())
315         {
316             ((SubqueryNode) rightOperand).setParentComparisonOperator(this);
317             return rightOperand.preprocess(numTables,
318                                            outerFromList, outerSubqueryList,
319                                            outerPredicateList);
320         }
321         else
322         {
323             rightOperand = rightOperand.preprocess(numTables,
324                                                    outerFromList, outerSubqueryList,
325                                                    outerPredicateList);
326             return this;
327         }
328     }
329
330     /**
331      * Eliminate NotNodes in the current query block. We traverse the tree,
332      * inverting ANDs and ORs and eliminating NOTs as we go. We stop at
333      * ComparisonOperators and boolean expressions. We invert
334      * ComparisonOperators and replace boolean expressions with
335      * boolean expression = false.
336      * NOTE: Since we do not recurse under ComparisonOperators, there
337      * still could be NotNodes left in the tree.
338      *
339      * @param underNotNode Whether or not we are under a NotNode.
340      *
341      *
342      * @return The modified expression
343      *
344      * @exception StandardException Thrown on error
345      */

346     ValueNode eliminateNots(boolean underNotNode)
347                     throws StandardException
348     {
349         if (! underNotNode)
350         {
351             return this;
352         }
353
354         /* Convert the BinaryComparison operator to its negation */
355         return getNegation(leftOperand, rightOperand);
356     }
357
358     /**
359      * Negate the comparison.
360      *
361      * @param leftOperand The left operand of the comparison operator
362      * @param rightOperand The right operand of the comparison operator
363      *
364      * @return BinaryOperatorNode The negated expression
365      *
366      * @exception StandardException Thrown on error
367      */

368     BinaryOperatorNode getNegation(ValueNode leftOperand,
369                                           ValueNode rightOperand)
370                 throws StandardException
371     {
372         /* Keep the compiler happy - this method should never be called.
373          * We should always be calling the method in a sub-class.
374          */

375         if (SanityManager.DEBUG)
376         SanityManager.ASSERT(false,
377                     "expected to call getNegation() for subclass " +
378                     getClass().toString());
379         return this;
380     }
381
382     /**
383      * Finish putting an expression into conjunctive normal
384      * form. An expression tree in conjunctive normal form meets
385      * the following criteria:
386      * o If the expression tree is not null,
387      * the top level will be a chain of AndNodes terminating
388      * in a true BooleanConstantNode.
389      * o The left child of an AndNode will never be an AndNode.
390      * o Any right-linked chain that includes an AndNode will
391      * be entirely composed of AndNodes terminated by a true BooleanConstantNode.
392      * o The left child of an OrNode will never be an OrNode.
393      * o Any right-linked chain that includes an OrNode will
394      * be entirely composed of OrNodes terminated by a false BooleanConstantNode.
395      * o ValueNodes other than AndNodes and OrNodes are considered
396      * leaf nodes for purposes of expression normalization.
397      * In other words, we won't do any normalization under
398      * those nodes.
399      *
400      * In addition, we track whether or not we are under a top level AndNode.
401      * SubqueryNodes need to know this for subquery flattening.
402      *
403      * @param underTopAndNode Whether or not we are under a top level AndNode.
404      *
405      *
406      * @return The modified expression
407      *
408      * @exception StandardException Thrown on error
409      */

410     public ValueNode changeToCNF(boolean underTopAndNode)
411                     throws StandardException
412     {
413         /* If our right child is a subquery and we are under a top and node
414          * then we want to mark the subquery as under a top and node.
415          * That will allow us to consider flattening it.
416          */

417         if (underTopAndNode && (rightOperand instanceof SubqueryNode))
418         {
419             rightOperand = rightOperand.changeToCNF(underTopAndNode);
420         }
421
422         return this;
423     }
424     
425     /** @see BinaryOperatorNode#genSQLJavaSQLTree */
426     public ValueNode genSQLJavaSQLTree() throws StandardException
427     {
428         TypeId leftTypeId = leftOperand.getTypeId();
429
430         /* If I have Java types, I need only add java->sql->java if the types
431          * are not comparable
432          */

433         if (leftTypeId.userType())
434         {
435             if (leftOperand.getTypeCompiler().comparable(leftTypeId, false,
436                                                            getClassFactory()))
437                 return this;
438
439             leftOperand = leftOperand.genSQLJavaSQLTree();
440         }
441
442         TypeId rightTypeId = rightOperand.getTypeId();
443
444         if (rightTypeId.userType())
445         {
446             if (rightOperand.getTypeCompiler().comparable(rightTypeId, false,
447                                                             getClassFactory()))
448                 return this;
449
450             rightOperand = rightOperand.genSQLJavaSQLTree();
451         }
452
453         return this;
454     }
455 }
456
Popular Tags