KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.ColumnReference
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.compile.NodeFactory;
26
27 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
28 import org.apache.derby.iapi.types.DataTypeDescriptor;
29
30 import org.apache.derby.iapi.error.StandardException;
31 import org.apache.derby.iapi.reference.SQLState;
32
33 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
34 import org.apache.derby.iapi.services.compiler.MethodBuilder;
35
36 import org.apache.derby.iapi.services.sanity.SanityManager;
37
38 import org.apache.derby.iapi.store.access.Qualifier;
39
40 import org.apache.derby.iapi.util.JBitSet;
41
42 import java.util.Vector JavaDoc;
43
44 /**
45  * A ColumnReference represents a column in the query tree. The parser generates a
46  * ColumnReference for each column reference. A column refercence could be a column in
47  * a base table, a column in a view (which could expand into a complex
48  * expression), or a column in a subquery in the FROM clause.
49  *
50  * @author Jerry Brenner
51  */

52
53 public class ColumnReference extends ValueNode
54 {
55     String JavaDoc columnName;
56
57     /*
58     ** This is the user-specified table name. It will be null if the
59     ** user specifies a column without a table name. Leave it null even
60     ** when the column is bound as it is only used in binding.
61     */

62     TableName tableName;
63     /* The table this column reference is bound to */
64     private int tableNumber;
65     /* The column number in the underlying base table */
66     private int columnNumber;
67     /* This is where the value for this column reference will be coming from */
68     private ResultColumn source;
69
70     /* For unRemapping */
71     ResultColumn origSource;
72     private String JavaDoc origName;
73     int origTableNumber = -1;
74     int origColumnNumber = -1;
75
76     /* Reuse generated code where possible */
77     //Expression genResult;
78

79     private boolean replacesAggregate;
80
81     private int nestingLevel = -1;
82     private int sourceLevel = -1;
83
84     /* Whether or not this column reference been scoped for the
85        sake of predicate pushdown.
86      */

87     private boolean scoped;
88
89     /* List of saved remap data if this ColumnReference is scoped
90        and has been remapped multiple times.
91      */

92     private java.util.ArrayList JavaDoc remaps;
93
94     /**
95      * Initializer.
96      * This one is called by the parser where we could
97      * be dealing with delimited identifiers.
98      *
99      * @param columnName The name of the column being referenced
100      * @param tableName The qualification for the column
101      * @param tokBeginOffset begin position of token for the column name
102      * identifier from parser.
103      * @param tokEndOffset end position of token for the column name
104      * identifier from parser.
105      */

106
107     public void init(Object JavaDoc columnName,
108                      Object JavaDoc tableName,
109                      Object JavaDoc tokBeginOffset,
110                      Object JavaDoc tokEndOffset
111                      )
112     {
113         this.columnName = (String JavaDoc) columnName;
114         this.tableName = (TableName) tableName;
115         this.setBeginOffset(((Integer JavaDoc) tokBeginOffset).intValue());
116         this.setEndOffset(((Integer JavaDoc) tokEndOffset).intValue());
117         tableNumber = -1;
118         remaps = null;
119     }
120
121     /**
122      * Initializer.
123      *
124      * @param columnName The name of the column being referenced
125      * @param tableName The qualification for the column
126      */

127
128     public void init(Object JavaDoc columnName, Object JavaDoc tableName)
129     {
130         this.columnName = (String JavaDoc) columnName;
131         this.tableName = (TableName) tableName;
132         tableNumber = -1;
133         remaps = null;
134     }
135
136     /**
137      * Convert this object to a String. See comments in QueryTreeNode.java
138      * for how this should be done for tree printing.
139      *
140      * @return This object as a String
141      */

142
143     public String JavaDoc toString()
144     {
145         if (SanityManager.DEBUG)
146         {
147             return "columnName: " + columnName + "\n" +
148                 "tableNumber: " + tableNumber + "\n" +
149                 "columnNumber: " + columnNumber + "\n" +
150                 "replacesAggregate: " + replacesAggregate + "\n" +
151                 "tableName: " + ( ( tableName != null) ? tableName.toString() : "null") + "\n" +
152                 "nestingLevel: " + nestingLevel + "\n" +
153                 "sourceLevel: " + sourceLevel + "\n" +
154                 super.toString();
155         }
156         else
157         {
158             return "";
159         }
160     }
161
162     /**
163      * Prints the sub-nodes of this object. See QueryTreeNode.java for
164      * how tree printing is supposed to work.
165      *
166      * @param depth The depth of this node in the tree
167      */

168
169     public void printSubNodes(int depth)
170     {
171         if (SanityManager.DEBUG)
172         {
173             super.printSubNodes(depth);
174
175             if (source != null)
176             {
177                 printLabel(depth, "source: ");
178                 source.treePrint(depth + 1);
179             }
180         }
181     }
182
183     /**
184      * Return whether or not this CR is correlated.
185      *
186      * @return Whether or not this CR is correlated.
187      */

188     boolean getCorrelated()
189     {
190         if (SanityManager.DEBUG)
191         {
192             SanityManager.ASSERT(nestingLevel != -1,
193                 "nestingLevel on "+columnName+" is not expected to be -1");
194             SanityManager.ASSERT(sourceLevel != -1,
195                 "sourceLevel on "+columnName+" is not expected to be -1");
196         }
197         return sourceLevel != nestingLevel;
198     }
199
200     /**
201      * Set the nesting level for this CR. (The nesting level
202      * at which the CR appears.)
203      *
204      * @param nestingLevel The Nesting level at which the CR appears.
205      */

206     void setNestingLevel(int nestingLevel)
207     {
208         if (SanityManager.DEBUG)
209         {
210             SanityManager.ASSERT(nestingLevel != -1,
211                 "nestingLevel is not expected to be -1");
212         }
213         this.nestingLevel = nestingLevel;
214     }
215
216     /**
217      * Get the nesting level for this CR.
218      *
219      * @return The nesting level for this CR.
220      */

221     int getNestingLevel()
222     {
223         return nestingLevel;
224     }
225
226     /**
227      * Set the source level for this CR. (The nesting level
228      * of the source of the CR.)
229      *
230      * @param sourceLevel The Nesting level of the source of the CR.
231      */

232     void setSourceLevel(int sourceLevel)
233     {
234         if (SanityManager.DEBUG)
235         {
236             SanityManager.ASSERT(sourceLevel != -1,
237                 "sourceLevel is not expected to be -1");
238         }
239         this.sourceLevel = sourceLevel;
240     }
241
242     /**
243      * Get the source level for this CR.
244      *
245      * @return The source level for this CR.
246      */

247     int getSourceLevel()
248     {
249         return sourceLevel;
250     }
251
252     /**
253      * Mark this node as being generated to replace an aggregate.
254      * (Useful for replacing aggregates in the HAVING clause with
255      * column references to the matching aggregate in the
256      * user's SELECT.
257      */

258     public void markGeneratedToReplaceAggregate()
259     {
260         replacesAggregate = true;
261     }
262
263     /**
264      * Determine whether or not this node was generated to
265      * replace an aggregate in the user's SELECT.
266      *
267      * @return boolean Whether or not this node was generated to replace
268      * an aggregate in the user's SELECT.
269      */

270     public boolean getGeneratedToReplaceAggregate()
271     {
272         return replacesAggregate;
273     }
274
275     /**
276      * Return a clone of this node.
277      *
278      * @return ValueNode A clone of this node.
279      *
280      * @exception StandardException Thrown on error
281      */

282     public ValueNode getClone()
283         throws StandardException
284     {
285         ColumnReference newCR = (ColumnReference) getNodeFactory().getNode(
286                                     C_NodeTypes.COLUMN_REFERENCE,
287                                     columnName,
288                                     tableName,
289                                     getContextManager());
290
291         newCR.copyFields(this);
292         return newCR;
293     }
294
295     /**
296      * Copy all of the "appropriate fields" for a shallow copy.
297      *
298      * @param oldCR The ColumnReference to copy from.
299      *
300      * @exception StandardException Thrown on error
301      */

302     public void copyFields(ColumnReference oldCR)
303         throws StandardException
304     {
305         super.copyFields(oldCR);
306
307         tableName = oldCR.getTableNameNode();
308         tableNumber = oldCR.getTableNumber();
309         columnNumber = oldCR.getColumnNumber();
310         source = oldCR.getSource();
311         nestingLevel = oldCR.getNestingLevel();
312         sourceLevel = oldCR.getSourceLevel();
313         replacesAggregate = oldCR.getGeneratedToReplaceAggregate();
314         scoped = oldCR.isScoped();
315     }
316
317     /**
318      * Bind this expression. This means binding the sub-expressions,
319      * as well as figuring out what the return type is for this expression.
320      *
321      * NOTE: We must explicitly check for a null FromList here, column reference
322      * without a FROM list, as the grammar allows the following:
323      * insert into t1 values(c1)
324      *
325      * @param fromList The FROM list for the query this
326      * expression is in, for binding columns.
327      * @param subqueryList The subquery list being built as we find SubqueryNodes
328      * @param aggregateVector The aggregate vector being built as we find AggregateNodes
329      *
330      * @return The new top of the expression tree.
331      *
332      * @exception StandardException Thrown on error
333      */

334
335     public ValueNode bindExpression(FromList fromList, SubqueryList subqueryList,
336             Vector JavaDoc aggregateVector)
337                 throws StandardException
338     {
339         ResultColumn matchingRC;
340
341         if (SanityManager.DEBUG)
342         {
343             SanityManager.ASSERT(fromList != null, "fromList is expected to be non-null");
344         }
345
346         if (fromList.size() == 0)
347         {
348             throw StandardException.newException(SQLState.LANG_ILLEGAL_COLUMN_REFERENCE, columnName);
349         }
350
351         matchingRC = fromList.bindColumnReference(this);
352
353         /* Error if no match found in fromList */
354         if (matchingRC == null)
355         {
356             throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND, getSQLColumnName());
357         }
358
359         /* Set the columnNumber from the base table.
360          * Useful for optimizer and generation.
361          */

362         columnNumber = matchingRC.getColumnPosition();
363
364         return this;
365     }
366
367     /**
368      * Get the column name for purposes of error
369      * messages or debugging. This returns the column
370      * name as used in the SQL statement. Thus if it was qualified
371      * with a table, alias name that will be included.
372      *
373      * @return The column name in the form [[schema.]table.]column
374      */

375
376     public String JavaDoc getSQLColumnName()
377     {
378         if (tableName == null)
379             return columnName;
380         
381         return tableName.toString() + "." + columnName;
382     }
383
384     /**
385      * Get the name of this column
386      *
387      * @return The name of this column
388      */

389
390     public String JavaDoc getColumnName()
391     {
392         return columnName;
393     }
394
395     /**
396      * Set the name of this column
397      *
398      * @param columnName The name of this column
399      */

400
401     public void setColumnName(String JavaDoc columnName)
402     {
403         this.columnName = columnName;
404     }
405
406     /**
407      * Get the table number for this ColumnReference.
408      *
409      * @return int The table number for this ColumnReference
410      */

411
412     public int getTableNumber()
413     {
414         return tableNumber;
415     }
416
417     /**
418      * Set this ColumnReference to refer to the given table number.
419      *
420      * @param tableNumber The table number this ColumnReference will refer to
421      */

422
423     public void setTableNumber(int tableNumber)
424     {
425         if (SanityManager.DEBUG)
426         {
427             SanityManager.ASSERT(tableNumber != -1,
428                 "tableNumber not expected to be -1");
429         }
430         this.tableNumber = tableNumber;
431     }
432
433     /**
434      * Get the user-supplied table name of this column. This will be null
435      * if the user did not supply a name (for example, select a from t).
436      * The method will return B for this example, select b.a from t as b
437      * The method will return T for this example, select t.a from t
438      *
439      * @return The user-supplied name of this column. Null if no user-
440      * supplied name.
441      */

442
443     public String JavaDoc getTableName()
444     {
445         return ( ( tableName != null) ? tableName.getTableName() : null );
446     }
447
448     /**
449      * Get the name of the underlying(base) table this column comes from, if any.
450      * Following example queries will all return T
451      * select a from t
452      * select b.a from t as b
453      * select t.a from t
454      *
455      * @return The name of the base table that this column comes from.
456      * Null if not a ColumnReference.
457      */

458
459     public String JavaDoc getSourceTableName()
460     {
461         return ((source != null) ? source.getTableName() : null);
462     }
463
464     /**
465      * Get the name of the schema for the Column's base table, if any.
466      * Following example queries will all return APP (assuming user is in schema APP)
467      * select t.a from t
468      * select b.a from t as b
469      * select app.t.a from t
470      *
471      * @return The name of the schema for Column's base table. If the column
472      * is not in a schema (i.e. is a derived column), it returns NULL.
473      */

474     public String JavaDoc getSourceSchemaName() throws StandardException
475     {
476         return ((source != null) ? source.getSchemaName() : null);
477     }
478
479     /**
480      * Is the column wirtable by the cursor or not. (ie, is it in the list of FOR UPDATE columns list)
481      *
482      * @return TRUE, if the column is a base column of a table and is
483      * writable by cursor.
484      */

485     public boolean updatableByCursor()
486     {
487         return ((source != null) ? source.updatableByCursor() : false);
488     }
489
490     /**
491       Return the table name as the node it is.
492       @return the column's table name.
493      */

494     public TableName getTableNameNode()
495     {
496         return tableName;
497     }
498
499     public void setTableNameNode(TableName tableName)
500     {
501         this.tableName = tableName;
502     }
503
504     /**
505      * Get the column number for this ColumnReference.
506      *
507      * @return int The column number for this ColumnReference
508      */

509
510     public int getColumnNumber()
511     {
512         return columnNumber;
513     }
514
515     /**
516      * Set the column number for this ColumnReference. This is
517      * used when scoping predicates for pushdown.
518      *
519      * @param colNum The new column number.
520      */

521
522     public void setColumnNumber(int colNum)
523     {
524         this.columnNumber = colNum;
525     }
526
527     /**
528      * Get the source this columnReference
529      *
530      * @return The source of this columnReference
531      */

532
533     public ResultColumn getSource()
534     {
535         return source;
536     }
537
538     /**
539      * Set the source this columnReference
540      *
541      * @param source The source of this columnReference
542      */

543
544     public void setSource(ResultColumn source)
545     {
546         this.source = source;
547     }
548
549     /**
550      * Do the 1st step in putting an expression into conjunctive normal
551      * form. This step ensures that the top level of the expression is
552      * a chain of AndNodes.
553      *
554      * @return The modified expression
555      *
556      * @exception StandardException Thrown on error
557      */

558     public ValueNode putAndsOnTop()
559                     throws StandardException
560     {
561         BinaryComparisonOperatorNode equalsNode;
562         BooleanConstantNode trueNode;
563         NodeFactory nodeFactory = getNodeFactory();
564         ValueNode andNode;
565
566         trueNode = (BooleanConstantNode) nodeFactory.getNode(
567                                         C_NodeTypes.BOOLEAN_CONSTANT_NODE,
568                                         Boolean.TRUE,
569                                         getContextManager());
570         equalsNode = (BinaryComparisonOperatorNode)
571                         nodeFactory.getNode(
572                                         C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE,
573                                         this,
574                                         trueNode,
575                                         getContextManager());
576         /* Set type info for the operator node */
577         equalsNode.bindComparisonOperator();
578         andNode = (ValueNode) nodeFactory.getNode(
579                                     C_NodeTypes.AND_NODE,
580                                     equalsNode,
581                                     trueNode,
582                                     getContextManager());
583         ((AndNode) andNode).postBindFixup();
584         return andNode;
585     }
586
587     /**
588      * Categorize this predicate. Initially, this means
589      * building a bit map of the referenced tables for each predicate.
590      * If the source of this ColumnReference (at the next underlying level)
591      * is not a ColumnReference or a VirtualColumnNode then this predicate
592      * will not be pushed down.
593      *
594      * For example, in:
595      * select * from (select 1 from s) a (x) where x = 1
596      * we will not push down x = 1.
597      * NOTE: It would be easy to handle the case of a constant, but if the
598      * inner SELECT returns an arbitrary expression, then we would have to copy
599      * that tree into the pushed predicate, and that tree could contain
600      * subqueries and method calls.
601      *
602      * Also, don't allow a predicate to be pushed down if it contains a
603      * ColumnReference that replaces an aggregate. This can happen if
604      * the aggregate is in the HAVING clause. In this case, we would be
605      * pushing the predicate into the SelectNode that evaluates the aggregate,
606      * which doesn't make sense, since the having clause is supposed to be
607      * applied to the result of the SelectNode.
608      *
609      * RESOLVE - revisit this issue once we have views.
610      *
611      * @param referencedTabs JBitSet with bit map of referenced FromTables
612      * @param simplePredsOnly Whether or not to consider method
613      * calls, field references and conditional nodes
614      * when building bit map
615      *
616      * @return boolean Whether or not source.expression is a ColumnReference
617      * or a VirtualColumnNode or a ConstantNode.
618      */

619     public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)
620     {
621         if (SanityManager.DEBUG)
622         SanityManager.ASSERT(tableNumber >= 0,
623                              "tableNumber is expected to be non-negative");
624         referencedTabs.set(tableNumber);
625
626         return ( ! replacesAggregate ) &&
627                ( (source.getExpression() instanceof ColumnReference) ||
628                  (source.getExpression() instanceof VirtualColumnNode) ||
629                  (source.getExpression() instanceof ConstantNode));
630     }
631
632     /**
633      * Remap all of the ColumnReferences in this expression tree
634      * to point to the ResultColumn that is 1 level under their
635      * current source ResultColumn.
636      * This is useful for pushing down single table predicates.
637      *
638      * RESOLVE: Once we start pushing join clauses, we will need to walk the
639      * ResultColumn/VirtualColumnNode chain for them to remap the references.
640      */

641     public void remapColumnReferences()
642     {
643         ValueNode expression = source.getExpression();
644
645         if (SanityManager.DEBUG)
646         {
647             // SanityManager.ASSERT(origSource == null,
648
// "Trying to remap ColumnReference twice without unremapping it.");
649
}
650
651         if ( ! ( (expression instanceof VirtualColumnNode) ||
652                  (expression instanceof ColumnReference) )
653             )
654         {
655             return;
656         }
657
658         /* Scoped column references are a special case: they can be
659          * remapped several times (once for every ProjectRestrictNode
660          * through which the scoped ColumnReference is pushed before
661          * reaching its target result set) and will be un-remapped
662          * several times, as well (as the scoped predicate is "pulled"
663          * back up the query tree to it's original location). So we
664          * have to keep track of the "orig" info for every remap
665          * operation, not just for the most recent one.
666          */

667         if (scoped && (origSource != null))
668         {
669             if (remaps == null)
670                 remaps = new java.util.ArrayList JavaDoc();
671             remaps.add(new RemapInfo(
672                 columnNumber, tableNumber, columnName, source));
673         }
674         else
675         {
676             origSource = source;
677             origName = columnName;
678             origColumnNumber = columnNumber;
679             origTableNumber = tableNumber;
680         }
681
682         /* Find the matching ResultColumn */
683         source = getSourceResultColumn();
684         columnName = source.getName();
685         columnNumber = source.getColumnPosition();
686
687         if (source.getExpression() instanceof ColumnReference)
688         {
689             ColumnReference cr = (ColumnReference) source.getExpression();
690             tableNumber = cr.getTableNumber();
691             if (SanityManager.DEBUG)
692             {
693                 // if dummy cr generated to replace aggregate, it may not have table number
694
// because underneath can be more than 1 table.
695
if (tableNumber == -1 && ! cr.getGeneratedToReplaceAggregate())
696                 {
697                     SanityManager.THROWASSERT(
698                         "tableNumber not expected to be -1, origName = " + origName);
699                 }
700             }
701         }
702     }
703
704     public void unRemapColumnReferences()
705     {
706         if (origSource == null)
707             return;
708
709         if (SanityManager.DEBUG)
710         {
711             // SanityManager.ASSERT(origSource != null,
712
// "Trying to unremap a ColumnReference that was not remapped.");
713
}
714
715         if ((remaps == null) || (remaps.size() == 0))
716         {
717             source = origSource;
718             origSource = null;
719             columnName = origName;
720             origName = null;
721             tableNumber = origTableNumber;
722             columnNumber = origColumnNumber;
723         }
724         else
725         {
726             // This CR is multiply-remapped, so undo the most
727
// recent (and only the most recent) remap operation.
728
RemapInfo rI = (RemapInfo)remaps.remove(remaps.size() - 1);
729             source = rI.getSource();
730             columnName = rI.getColumnName();
731             tableNumber = rI.getTableNumber();
732             columnNumber = rI.getColumnNumber();
733             rI = null;
734             if (remaps.size() == 0)
735                 remaps = null;
736         }
737     }
738
739     /**
740      * Returns true if this ColumnReference has been remapped; false
741      * otherwise.
742      *
743      * @return Whether or not this ColumnReference has been remapped.
744      */

745     protected boolean hasBeenRemapped()
746     {
747         return (origSource != null);
748     }
749
750     /*
751      * Get the ResultColumn that the source points to. This is useful for
752      * getting what the source will be after this ColumnReference is remapped.
753      */

754     public ResultColumn getSourceResultColumn()
755     {
756         ValueNode expression = source.getExpression();
757
758         /* Find the matching ResultColumn */
759         if (expression instanceof VirtualColumnNode)
760         {
761             return ((VirtualColumnNode) expression).getSourceResultColumn();
762         }
763         else
764         {
765             /* RESOLVE - If expression is a ColumnReference, then we are hitting
766              * the top of a query block (derived table or view.)
767              * In order to be able to push the expression down into the next
768              * query block, it looks like we should reset the contents of the
769              * current ColumnReference to be the same as expression. (This probably
770              * only means names and tableNumber.) We would then "rebind" the top
771              * level predicate somewhere up the call stack and see if we could push
772              * the predicate through.
773              */

774             return ((ColumnReference) expression).getSourceResultColumn();
775         }
776     }
777
778     /**
779      * Remap all ColumnReferences in this tree to be clones of the
780      * underlying expression.
781      *
782      * @return ValueNode The remapped expression tree.
783      *
784      * @exception StandardException Thrown on error
785      */

786     public ValueNode remapColumnReferencesToExpressions()
787         throws StandardException
788     {
789         ResultColumn rc;
790         ResultColumn sourceRC = source;
791
792         /* Nothing to do if we are not pointing to a redundant RC */
793         if (! source.isRedundant())
794         {
795             return this;
796         }
797
798         /* Find the last redundant RC in the chain. We
799          * want to clone its expression.
800          */

801         for (rc = source; rc != null && rc.isRedundant(); )
802         {
803             ResultColumn nextRC = null;
804             ValueNode expression = rc.getExpression();
805
806             /* Find the matching ResultColumn */
807             if (expression instanceof VirtualColumnNode)
808             {
809                 nextRC = ((VirtualColumnNode) expression).getSourceResultColumn();
810             }
811             else if (expression instanceof ColumnReference)
812             {
813                 nextRC = ((ColumnReference) expression).getSourceResultColumn();
814             }
815             else
816             {
817                 nextRC = null;
818             }
819
820             if (nextRC != null && nextRC.isRedundant())
821             {
822                 sourceRC = nextRC;
823             }
824             rc = nextRC;
825         }
826
827         if (SanityManager.DEBUG)
828         {
829             if (sourceRC == null)
830             {
831                 SanityManager.THROWASSERT(
832                     "sourceRC is expected to be non-null for " +
833                     columnName);
834             }
835
836             if ( ! sourceRC.isRedundant())
837             {
838                 SanityManager.THROWASSERT(
839                     "sourceRC is expected to be redundant for " +
840                     columnName);
841             }
842         }
843
844         /* If last expression is a VCN, then we can't clone it.
845          * Instead, we just reset our source to point to the
846          * source of the VCN, those chopping out the layers.
847          * Otherwise, we return a clone of the underlying expression.
848          */

849         if (sourceRC.getExpression() instanceof VirtualColumnNode)
850         {
851             VirtualColumnNode vcn =
852                 (VirtualColumnNode) (sourceRC.getExpression());
853             ResultSetNode rsn = vcn.getSourceResultSet();
854             if (rsn instanceof FromTable)
855             {
856                 tableNumber = ((FromTable) rsn).getTableNumber();
857                 if (SanityManager.DEBUG)
858                 {
859                     SanityManager.ASSERT(tableNumber != -1,
860                         "tableNumber not expected to be -1");
861                 }
862             }
863             else
864             {
865                 if (SanityManager.DEBUG)
866                 {
867                     SanityManager.THROWASSERT("rsn expected to be a FromTable, but is a " + rsn.getClass().getName());
868                 }
869             }
870             source = ((VirtualColumnNode) sourceRC.getExpression()).
871                                         getSourceResultColumn();
872             return this;
873         }
874         else
875         {
876             return sourceRC.getExpression().getClone();
877         }
878     }
879
880     /**
881      * Update the table map to reflect the source
882      * of this CR.
883      *
884      * @param refs The table map.
885      */

886     void getTablesReferenced(JBitSet refs)
887     {
888         if (refs.size() < tableNumber)
889             refs.grow(tableNumber);
890
891         if (tableNumber != -1) // it may not be set if replacesAggregate is true
892
refs.set(tableNumber);
893     }
894
895     /**
896      * Return whether or not this expression tree is cloneable.
897      *
898      * @return boolean Whether or not this expression tree is cloneable.
899      */

900     public boolean isCloneable()
901     {
902         return true;
903     }
904
905     /** @see ValueNode#constantExpression */
906     public boolean constantExpression(PredicateList whereClause)
907     {
908         return whereClause.constantColumn(this);
909     }
910
911     /**
912      * ColumnReference's are to the current row in the system.
913      * This lets us generate
914      * a faster get that simply returns the column from the
915      * current row, rather than getting the value out and
916      * returning that, only to have the caller (in the situations
917      * needed) stuffing it back into a new column holder object.
918      * We will assume the general generate() path is for getting
919      * the value out, and use generateColumn() when we want to
920      * keep the column wrapped.
921      *
922      * @exception StandardException Thrown on error
923      */

924      public void generateExpression(ExpressionClassBuilder acb,
925                                             MethodBuilder mb)
926                                     throws StandardException
927      {
928         int sourceResultSetNumber = source.getResultSetNumber();
929
930         //PUSHCOMPILE
931
/* Reuse generated code, where possible */
932
933         /*
934         ** If the source is redundant, return the generation of its source.
935         ** Most redundant nodes will be flattened out by this point, but
936         ** in at least one case (elimination of redundant ProjectRestricts
937         ** during generation) we don't do this.
938         */

939         if (source.isRedundant())
940         {
941             source.generateExpression(acb, mb);
942             return;
943         }
944
945         if (SanityManager.DEBUG)
946         {
947             if (sourceResultSetNumber < 0)
948             {
949                 SanityManager.THROWASSERT("sourceResultSetNumber expected to be >= 0 for " + getTableName() + "." + getColumnName());
950             }
951         }
952
953         /* The ColumnReference is from an immediately underlying ResultSet.
954          * The Row for that ResultSet is Activation.row[sourceResultSetNumber],
955          * where sourceResultSetNumber is the resultSetNumber for that ResultSet.
956          *
957          * The generated java is the expression:
958          * (<interface>) this.row[sourceResultSetNumber].getColumn(#columnId);
959          *
960          * where <interface> is the appropriate Datatype protocol interface
961          * for the type of the column.
962          */

963         acb.pushColumnReference(mb, sourceResultSetNumber,
964                                             source.getVirtualColumnId());
965
966         mb.cast(getTypeCompiler().interfaceName());
967
968         /* Remember generated code for possible resuse */
969      }
970
971     /**
972      * Get the user-supplied schema name of this column. This will be null
973      * if the user did not supply a name (for example, select t.a from t).
974      * Another example for null return value (for example, select b.a from t as b).
975      * But for following query select app.t.a from t, this will return APP
976      * Code generation of aggregate functions relies on this method
977      *
978      * @return The user-supplied schema name of this column. Null if no user-
979      * supplied name.
980      */

981
982     public String JavaDoc getSchemaName()
983     {
984         return ( ( tableName != null) ? tableName.getSchemaName() : null );
985     }
986
987     /**
988      * Return the variant type for the underlying expression.
989      * The variant type can be:
990      * VARIANT - variant within a scan
991      * (method calls and non-static field access)
992      * SCAN_INVARIANT - invariant within a scan
993      * (column references from outer tables)
994      * QUERY_INVARIANT - invariant within the life of a query
995      * (constant expressions)
996      *
997      * @return The variant type for the underlying expression.
998      */

999     protected int getOrderableVariantType()
1000    {
1001        // ColumnReferences are invariant for the life of the scan
1002
return Qualifier.SCAN_INVARIANT;
1003    }
1004
1005    /**
1006     * Return whether or not the source of this ColumnReference is itself a ColumnReference.
1007     *
1008     * @return Whether or not the source of this ColumnReference is itself a ColumnReference.
1009     */

1010    boolean pointsToColumnReference()
1011    {
1012        return (source.getExpression() instanceof ColumnReference);
1013    }
1014
1015    /**
1016     * Get the DataTypeServices from this Node.
1017     *
1018     * @return The DataTypeServices from this Node. This
1019     * may be null if the node isn't bound yet.
1020     */

1021    public DataTypeDescriptor getTypeServices() throws StandardException
1022    {
1023        DataTypeDescriptor dtd = super.getTypeServices();
1024        if( dtd == null && source != null)
1025        {
1026            dtd = source.getTypeServices();
1027            if( dtd != null)
1028                setType( dtd);
1029        }
1030        return dtd;
1031    } // end of getTypeServices
1032

1033    /**
1034     * Find the source result set for this ColumnReference and
1035     * return it. Also, when the source result set is found,
1036     * return the position (within the source result set's RCL)
1037     * of the column referenced by this ColumnReference. The
1038     * position is returned vai the colNum parameter.
1039     *
1040     * @param colNum Place to store the position of the column
1041     * to which this ColumnReference points (position is w.r.t
1042     * the source result set).
1043     * @return The source result set for this ColumnReference;
1044     * null if there is no source result set.
1045     */

1046    protected ResultSetNode getSourceResultSet(int [] colNum)
1047        throws StandardException
1048    {
1049        if (source == null)
1050        {
1051            /* this can happen if column reference is pointing to a column
1052             * that is not from a base table. For example, if we have a
1053             * VALUES clause like
1054             *
1055             * (values (1, 2), (3, 4)) V1 (i, j)
1056             *
1057             * and then a column reference to VI.i, the column reference
1058             * won't have a source.
1059             */

1060            return null;
1061        }
1062
1063        ValueNode rcExpr = null;
1064        ResultColumn rc = getSource();
1065
1066        // Walk the ResultColumn->ColumnReference chain until we
1067
// find a ResultColumn whose expression is a VirtualColumnNode.
1068

1069        rcExpr = rc.getExpression();
1070        colNum[0] = getColumnNumber();
1071
1072        /* We have to make sure we enter this loop if rc is redundant,
1073         * so that we can navigate down to the actual source result
1074         * set (DERBY-1777). If rc *is* redundant, then rcExpr is not
1075         * guaranteed to be a ColumnReference, so we have to check
1076         * for that case inside the loop.
1077         */

1078        while ((rcExpr != null) &&
1079            (rc.isRedundant() || (rcExpr instanceof ColumnReference)))
1080        {
1081            if (rcExpr instanceof ColumnReference)
1082            {
1083                colNum[0] = ((ColumnReference)rcExpr).getColumnNumber();
1084                rc = ((ColumnReference)rcExpr).getSource();
1085            }
1086
1087            /* If "rc" is redundant then that means it points to another
1088             * ResultColumn that in turn points to the source expression.
1089             * This can happen in cases where "rc" points to a subquery
1090             * that has been flattened into the query above it (flattening
1091             * of subqueries occurs during preprocessing). In that case
1092             * we want to skip over the redundant rc and find the
1093             * ResultColumn that actually holds the source expression.
1094             */

1095            while (rc.isRedundant())
1096            {
1097                rcExpr = rc.getExpression();
1098                if (rcExpr instanceof VirtualColumnNode)
1099                    rc = ((VirtualColumnNode)rcExpr).getSourceResultColumn();
1100                else if (rcExpr instanceof ColumnReference)
1101                {
1102                    colNum[0] = ((ColumnReference)rcExpr).getColumnNumber();
1103                    rc = ((ColumnReference)rcExpr).getSource();
1104                }
1105                else
1106                {
1107                    /* If rc isn't pointing to a VirtualColumnNode nor
1108                     * to a ColumnReference, then it's not pointing to
1109                     * a result set. It could, for example, be pointing
1110                     * to a constant node or to the result of an aggregate
1111                     * or function. Break out of both loops and return
1112                     * null since there is no source result set.
1113                     */

1114                    rcExpr = null;
1115                    break;
1116                }
1117            }
1118            rcExpr = rc.getExpression();
1119        }
1120
1121        // If we found a VirtualColumnNode, return the VirtualColumnNode's
1122
// sourceResultSet. The column within that sourceResultSet that
1123
// is referenced by this ColumnReference is also returned, via
1124
// the colNum parameter, and was set above.
1125
if ((rcExpr != null) && (rcExpr instanceof VirtualColumnNode))
1126            return ((VirtualColumnNode)rcExpr).getSourceResultSet();
1127
1128        // If we get here then the ColumnReference doesn't reference
1129
// a result set, so return null.
1130
colNum[0] = -1;
1131        return null;
1132    }
1133    
1134    protected boolean isEquivalent(ValueNode o) throws StandardException
1135    {
1136        if (!isSameNodeType(o)) {
1137            return false;
1138        }
1139        ColumnReference other = (ColumnReference)o;
1140        return (tableNumber == other.tableNumber
1141                && columnName.equals(other.getColumnName()));
1142    }
1143
1144    /**
1145     * Mark this column reference as "scoped", which means that it
1146     * was created (as a clone of another ColumnReference) to serve
1147     * as the left or right operand of a scoped predicate.
1148     */

1149    protected void markAsScoped()
1150    {
1151        scoped = true;
1152    }
1153
1154    /**
1155     * Return whether or not this ColumnReference is scoped.
1156     */

1157    protected boolean isScoped()
1158    {
1159        return scoped;
1160    }
1161
1162    /**
1163     * Helper class to keep track of remap data when a ColumnReference
1164     * is remapped multiple times. This allows the CR to be UN-
1165     * remapped multiple times, as well.
1166     */

1167    private class RemapInfo
1168    {
1169        int colNum;
1170        int tableNum;
1171        String JavaDoc colName;
1172        ResultColumn source;
1173
1174        RemapInfo(int cNum, int tNum, String JavaDoc cName, ResultColumn rc)
1175        {
1176            colNum = cNum;
1177            tableNum = tNum;
1178            colName = cName;
1179            source = rc;
1180        }
1181
1182        int getColumnNumber() { return colNum; }
1183        int getTableNumber() { return tableNum; }
1184        String JavaDoc getColumnName() { return colName; }
1185        ResultColumn getSource() { return source; }
1186
1187        void setColNumber(int cNum) { colNum = cNum; }
1188        void setTableNumber(int tNum) { tableNum = tNum; }
1189        void setColName(String JavaDoc cName) { colName = cName; }
1190        void setSource(ResultColumn rc) { source = rc; }
1191    }
1192}
1193
Popular Tags