001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.ValueNodeList
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.services.sanity.SanityManager;
025:
026: import org.apache.derby.iapi.error.StandardException;
027:
028: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
029:
030: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
031:
032: import org.apache.derby.iapi.types.DataTypeDescriptor;
033: import org.apache.derby.iapi.types.DataValueDescriptor;
034: import org.apache.derby.iapi.types.TypeId;
035:
036: import org.apache.derby.iapi.sql.compile.TypeCompiler;
037:
038: import org.apache.derby.iapi.reference.SQLState;
039:
040: import org.apache.derby.iapi.store.access.Qualifier;
041:
042: import org.apache.derby.iapi.util.JBitSet;
043:
044: import java.util.Vector;
045:
046: /**
047: * A ValueNodeList represents a list of ValueNodes within a specific predicate
048: * (eg, IN list, NOT IN list or BETWEEN) in a DML statement.
049: * It extends QueryTreeNodeVector.
050: *
051: * @author Jerry Brenner
052: */
053:
054: public class ValueNodeList extends QueryTreeNodeVector {
055:
056: /**
057: * Prints the sub-nodes of this object. See QueryTreeNode.java for
058: * how tree printing is supposed to work.
059: *
060: * @param depth The depth of this node in the tree
061: */
062:
063: public void printSubNodes(int depth) {
064: if (SanityManager.DEBUG) {
065: super .printSubNodes(depth);
066:
067: for (int index = 0; index < size(); index++) {
068: ValueNode valueNode;
069: valueNode = (ValueNode) elementAt(index);
070: valueNode.treePrint(depth + 1);
071: }
072: }
073: }
074:
075: /**
076: * Set the clause that this node appears in.
077: *
078: * @param clause The clause that this node appears in.
079: */
080: public void setClause(int clause) {
081: int size = size();
082:
083: for (int index = 0; index < size; index++) {
084: ValueNode valueNode;
085: valueNode = (ValueNode) elementAt(index);
086: valueNode.setClause(clause);
087: }
088: }
089:
090: /**
091: * Add a ValueNode to the list.
092: *
093: * @param valueNode A ValueNode to add to the list
094: *
095: * @exception StandardException Thrown on error
096: */
097:
098: public void addValueNode(ValueNode valueNode)
099: throws StandardException {
100: addElement(valueNode);
101: }
102:
103: /**
104: * Bind this expression. This means binding the sub-expressions,
105: * as well as figuring out what the return type is for this expression.
106: *
107: * @param fromList The FROM list for the query this
108: * expression is in, for binding columns.
109: * @param subqueryList The subquery list being built as we find SubqueryNodes
110: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
111: *
112: * @exception StandardException Thrown on error
113: */
114: public void bindExpression(FromList fromList,
115: SubqueryList subqueryList, Vector aggregateVector)
116: throws StandardException {
117: int size = size();
118:
119: for (int index = 0; index < size; index++) {
120: ValueNode vn = (ValueNode) elementAt(index);
121: vn = vn.bindExpression(fromList, subqueryList,
122: aggregateVector);
123:
124: setElementAt(vn, index);
125: }
126: }
127:
128: /**
129: * Generate a SQL->Java->SQL conversion tree any node in the list
130: * which is not a system built-in type.
131: * This is useful when doing comparisons, built-in functions, etc. on
132: * java types which have a direct mapping to system built-in types.
133: *
134: * @exception StandardException Thrown on error
135: */
136: public void genSQLJavaSQLTrees() throws StandardException {
137: int size = size();
138:
139: for (int index = 0; index < size; index++) {
140: ValueNode valueNode = (ValueNode) elementAt(index);
141:
142: if (valueNode.getTypeId().userType()) {
143: setElementAt(valueNode.genSQLJavaSQLTree(), index);
144: }
145: }
146: }
147:
148: /**
149: * Get the dominant DataTypeServices from the elements in the list.
150: *
151: * @return DataTypeServices The dominant DataTypeServices.
152: *
153: * @exception StandardException Thrown on error
154: */
155: public DataTypeDescriptor getDominantTypeServices()
156: throws StandardException {
157: DataTypeDescriptor dominantDTS = null;
158:
159: for (int index = 0; index < size(); index++) {
160: ValueNode valueNode;
161:
162: valueNode = (ValueNode) elementAt(index);
163: if (valueNode.requiresTypeFromContext())
164: continue;
165: DataTypeDescriptor valueNodeDTS = valueNode
166: .getTypeServices();
167:
168: if (dominantDTS == null) {
169: dominantDTS = valueNodeDTS;
170: } else {
171: dominantDTS = dominantDTS.getDominantType(valueNodeDTS,
172: getClassFactory());
173: }
174: }
175:
176: return dominantDTS;
177: }
178:
179: /**
180: * Get the first non-null DataTypeServices from the elements in the list.
181: *
182: * @return DataTypeServices The first non-null DataTypeServices.
183: *
184: * @exception StandardException Thrown on error
185: */
186: public DataTypeDescriptor getTypeServices()
187: throws StandardException {
188: DataTypeDescriptor firstDTS = null;
189: int size = size();
190:
191: for (int index = 0; index < size; index++) {
192: ValueNode valueNode;
193:
194: valueNode = (ValueNode) elementAt(index);
195: DataTypeDescriptor valueNodeDTS = valueNode
196: .getTypeServices();
197:
198: if ((firstDTS == null) && (valueNodeDTS != null)) {
199: firstDTS = valueNodeDTS;
200: break;
201: }
202: }
203:
204: return firstDTS;
205: }
206:
207: /**
208: * Return whether or not all of the entries in the list have the same
209: * type precendence as the specified value.
210: *
211: * @param precedence The specified precedence.
212: *
213: * @return Whether or not all of the entries in the list have the same
214: * type precendence as the specified value.
215: */
216: boolean allSamePrecendence(int precedence) throws StandardException {
217: boolean allSame = true;
218: int size = size();
219:
220: for (int index = 0; index < size; index++) {
221: ValueNode valueNode;
222:
223: valueNode = (ValueNode) elementAt(index);
224: DataTypeDescriptor valueNodeDTS = valueNode
225: .getTypeServices();
226:
227: if (valueNodeDTS == null) {
228: return false;
229: }
230:
231: if (precedence != valueNodeDTS.getTypeId().typePrecedence()) {
232: return false;
233: }
234: }
235:
236: return allSame;
237: }
238:
239: /**
240: * Make sure that passed ValueNode's type is compatible with the non-parameter elements in the ValueNodeList.
241: *
242: * @param leftOperand Check for compatibility against this parameter's type
243: *
244: */
245: public void compatible(ValueNode leftOperand)
246: throws StandardException {
247: int size = size();
248: TypeId leftType;
249: ValueNode valueNode;
250: TypeCompiler leftTC;
251:
252: leftType = leftOperand.getTypeId();
253: leftTC = leftOperand.getTypeCompiler();
254:
255: for (int index = 0; index < size; index++) {
256: valueNode = (ValueNode) elementAt(index);
257: if (valueNode.requiresTypeFromContext())
258: continue;
259:
260: /*
261: ** Are the types compatible to each other? If not, throw an exception.
262: */
263: if (!leftTC.compatible(valueNode.getTypeId())) {
264: throw StandardException.newException(
265: SQLState.LANG_DB2_COALESCE_DATATYPE_MISMATCH,
266: leftType.getSQLTypeName(), valueNode
267: .getTypeId().getSQLTypeName());
268: }
269: }
270: }
271:
272: /**
273: * Determine whether or not the leftOperand is comparable() with all of
274: * the elements in the list. Throw an exception if any of them are not
275: * comparable.
276: *
277: * @param leftOperand The left side of the expression
278: *
279: * @exception StandardException Thrown on error
280: */
281: public void comparable(ValueNode leftOperand)
282: throws StandardException {
283: int size = size();
284: TypeId leftType;
285: ValueNode valueNode;
286: TypeCompiler leftTC;
287:
288: leftType = leftOperand.getTypeId();
289: leftTC = leftOperand.getTypeCompiler();
290:
291: for (int index = 0; index < size; index++) {
292: valueNode = (ValueNode) elementAt(index);
293:
294: /*
295: ** Can the types be compared to each other? If not, throw an
296: ** exception.
297: */
298: if (!leftTC.comparable(valueNode.getTypeId(), false,
299: getClassFactory())) {
300: throw StandardException.newException(
301: SQLState.LANG_NOT_COMPARABLE, leftType
302: .getSQLTypeName(), valueNode
303: .getTypeId().getSQLTypeName());
304: }
305: }
306: }
307:
308: /**
309: * Determine whether or not any of the elements in the list are nullable.
310: *
311: * @return boolean Whether or not any of the elements in the list
312: * are nullable.
313: */
314: public boolean isNullable() throws StandardException {
315: int size = size();
316:
317: for (int index = 0; index < size; index++) {
318: if (((ValueNode) elementAt(index)).getTypeServices()
319: .isNullable()) {
320: return true;
321: }
322: }
323: return false;
324: }
325:
326: /**
327: * Does this list contain a ParameterNode?
328: *
329: * @return boolean Whether or not the list contains a ParameterNode
330: */
331: public boolean containsParameterNode() {
332: int size = size();
333:
334: for (int index = 0; index < size; index++) {
335: if (((ValueNode) elementAt(index))
336: .requiresTypeFromContext()) {
337: return true;
338: }
339: }
340: return false;
341: }
342:
343: /**
344: * Does this list contain all ParameterNodes?
345: *
346: * @return boolean Whether or not the list contains all ParameterNodes
347: */
348: public boolean containsAllParameterNodes() {
349: int size = size();
350:
351: for (int index = 0; index < size; index++) {
352: if (!(((ValueNode) elementAt(index))
353: .requiresTypeFromContext())) {
354: return false;
355: }
356: }
357: return true;
358: }
359:
360: /**
361: * Does this list contain all ConstantNodes?
362: *
363: * @return boolean Whether or not the list contains all ConstantNodes
364: */
365: public boolean containsAllConstantNodes() {
366: int size = size();
367:
368: for (int index = 0; index < size; index++) {
369: if (!((ValueNode) elementAt(index) instanceof ConstantNode)) {
370: return false;
371: }
372: }
373: return true;
374: }
375:
376: /**
377: * Sort the entries in the list in ascending order.
378: * (All values are assumed to be constants.)
379: *
380: * @param judgeODV In case of type not exactly matching, the judging type.
381: *
382: * @exception StandardException Thrown on error
383: */
384: void sortInAscendingOrder(DataValueDescriptor judgeODV)
385: throws StandardException {
386: int size = size();
387:
388: if (SanityManager.DEBUG) {
389: SanityManager.ASSERT(size > 0,
390: "size() expected to be non-zero");
391: }
392:
393: /* We use bubble sort to sort the list since we expect
394: * the list to be in sorted order > 90% of the time.
395: */
396: boolean continueSort = true;
397:
398: while (continueSort) {
399: continueSort = false;
400:
401: for (int index = 1; index < size; index++) {
402: ConstantNode currCN = (ConstantNode) elementAt(index);
403: DataValueDescriptor currODV = currCN.getValue();
404: ConstantNode prevCN = (ConstantNode) elementAt(index - 1);
405: DataValueDescriptor prevODV = prevCN.getValue();
406:
407: /* Swap curr and prev if prev > curr */
408: if ((judgeODV == null && (prevODV.compare(currODV)) > 0)
409: || (judgeODV != null && judgeODV.greaterThan(
410: prevODV, currODV).equals(true))) {
411: setElementAt(currCN, index - 1);
412: setElementAt(prevCN, index);
413: continueSort = true;
414: }
415: }
416: }
417: }
418:
419: /**
420: * Set the descriptor for every ParameterNode in the list.
421: *
422: * @param descriptor The DataTypeServices to set for the parameters
423: *
424: * @exception StandardException Thrown on error
425: */
426: public void setParameterDescriptor(DataTypeDescriptor descriptor)
427: throws StandardException {
428: int size = size();
429: ValueNode valueNode;
430:
431: for (int index = 0; index < size; index++) {
432: valueNode = (ValueNode) elementAt(index);
433: if (valueNode.requiresTypeFromContext()) {
434: valueNode.setType(descriptor);
435: }
436: }
437: }
438:
439: /**
440: * Preprocess a ValueNodeList. For now, we just preprocess each ValueNode
441: * in the list.
442: *
443: * @param numTables Number of tables in the DML Statement
444: * @param outerFromList FromList from outer query block
445: * @param outerSubqueryList SubqueryList from outer query block
446: * @param outerPredicateList PredicateList from outer query block
447: *
448: * @exception StandardException Thrown on error
449: */
450: public void preprocess(int numTables, FromList outerFromList,
451: SubqueryList outerSubqueryList,
452: PredicateList outerPredicateList) throws StandardException {
453: int size = size();
454: ValueNode valueNode;
455:
456: for (int index = 0; index < size; index++) {
457: valueNode = (ValueNode) elementAt(index);
458: valueNode.preprocess(numTables, outerFromList,
459: outerSubqueryList, outerPredicateList);
460: }
461: }
462:
463: /**
464: * Remap all ColumnReferences in this tree to be clones of the
465: * underlying expression.
466: *
467: * @return ValueNodeList The remapped expression tree.
468: *
469: * @exception StandardException Thrown on error
470: */
471: public ValueNodeList remapColumnReferencesToExpressions()
472: throws StandardException {
473: int size = size();
474:
475: for (int index = 0; index < size; index++) {
476: setElementAt(((ValueNode) elementAt(index))
477: .remapColumnReferencesToExpressions(), index);
478: }
479: return this ;
480: }
481:
482: /**
483: * Return whether or not this expression tree represents a constant expression.
484: *
485: * @return Whether or not this expression tree represents a constant expression.
486: */
487: public boolean isConstantExpression() {
488: int size = size();
489:
490: for (int index = 0; index < size; index++) {
491: boolean retcode;
492:
493: retcode = ((ValueNode) elementAt(index))
494: .isConstantExpression();
495: if (!retcode) {
496: return retcode;
497: }
498: }
499:
500: return true;
501: }
502:
503: /** @see ValueNode#constantExpression */
504: public boolean constantExpression(PredicateList whereClause) {
505: int size = size();
506:
507: for (int index = 0; index < size; index++) {
508: boolean retcode;
509:
510: retcode = ((ValueNode) elementAt(index))
511: .constantExpression(whereClause);
512: if (!retcode) {
513: return retcode;
514: }
515: }
516:
517: return true;
518: }
519:
520: /**
521: * Categorize this predicate. Initially, this means
522: * building a bit map of the referenced tables for each predicate.
523: * If the source of this ColumnReference (at the next underlying level)
524: * is not a ColumnReference or a VirtualColumnNode then this predicate
525: * will not be pushed down.
526: *
527: * For example, in:
528: * select * from (select 1 from s) a (x) where x = 1
529: * we will not push down x = 1.
530: * NOTE: It would be easy to handle the case of a constant, but if the
531: * inner SELECT returns an arbitrary expression, then we would have to copy
532: * that tree into the pushed predicate, and that tree could contain
533: * subqueries and method calls.
534: * RESOLVE - revisit this issue once we have views.
535: *
536: * @param referencedTabs JBitSet with bit map of referenced FromTables
537: * @param simplePredsOnly Whether or not to consider method
538: * calls, field references and conditional nodes
539: * when building bit map
540: *
541: * @return boolean Whether or not source.expression is a ColumnReference
542: * or a VirtualColumnNode.
543: * @exception StandardException Thrown on error
544: */
545: public boolean categorize(JBitSet referencedTabs,
546: boolean simplePredsOnly) throws StandardException {
547: /* We stop here when only considering simple predicates
548: * as we don't consider in lists when looking
549: * for null invariant predicates.
550: */
551: boolean pushable = true;
552: int size = size();
553:
554: for (int index = 0; index < size; index++) {
555: pushable = ((ValueNode) elementAt(index)).categorize(
556: referencedTabs, simplePredsOnly)
557: && pushable;
558: }
559:
560: return pushable;
561: }
562:
563: /**
564: * Return the variant type for the underlying expression.
565: * The variant type can be:
566: * VARIANT - variant within a scan
567: * (method calls and non-static field access)
568: * SCAN_INVARIANT - invariant within a scan
569: * (column references from outer tables)
570: * QUERY_INVARIANT - invariant within the life of a query
571: * CONSTANT - constant
572: *
573: * @return The variant type for the underlying expression.
574: * @exception StandardException thrown on error
575: */
576: protected int getOrderableVariantType() throws StandardException {
577: int listType = Qualifier.CONSTANT;
578: int size = size();
579:
580: /* If any element in the list is VARIANT then the
581: * entire expression is variant
582: * else it is SCAN_INVARIANT if any element is SCAN_INVARIANT
583: * else it is QUERY_INVARIANT.
584: */
585: for (int index = 0; index < size; index++) {
586: int curType = ((ValueNode) elementAt(index))
587: .getOrderableVariantType();
588: listType = Math.min(listType, curType);
589: }
590:
591: return listType;
592: }
593: }
|