KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2    Derby - Class org.apache.derby.impl.sql.compile.ResultColumnList
3
4    Licensed to the Apache Software Foundation (ASF) under one or more
5    contributor license agreements. See the NOTICE file distributed with
6    this work for additional information regarding copyright ownership.
7    The ASF licenses this file to you under the Apache License, Version 2.0
8    (the "License"); you may not use this file except in compliance with
9    the License. You may obtain a copy of the License at
10
11       http://www.apache.org/licenses/LICENSE-2.0
12
13    Unless required by applicable law or agreed to in writing, software
14    distributed under the License is distributed on an "AS IS" BASIS,
15    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16    See the License for the specific language governing permissions and
17    limitations under the License.
18
19  */

20
21 package org.apache.derby.impl.sql.compile;
22
23
24 import org.apache.derby.iapi.services.context.ContextManager;
25 import org.apache.derby.iapi.services.compiler.MethodBuilder;
26 import org.apache.derby.iapi.services.compiler.LocalField;
27
28 import org.apache.derby.iapi.services.sanity.SanityManager;
29 import org.apache.derby.iapi.services.monitor.Monitor;
30 import org.apache.derby.iapi.services.loader.ClassFactory;
31 import org.apache.derby.iapi.services.io.Storable;
32 import org.apache.derby.iapi.services.context.ContextManager;
33
34 import org.apache.derby.iapi.error.StandardException;
35
36 import org.apache.derby.iapi.sql.compile.NodeFactory;
37 import org.apache.derby.iapi.sql.compile.CompilerContext;
38 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
39
40 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
41
42 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
43 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
44 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
45 import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
46 import org.apache.derby.iapi.sql.dictionary.DefaultDescriptor;
47 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
48 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
49
50 import org.apache.derby.iapi.types.TypeId;
51 import org.apache.derby.iapi.services.classfile.VMOpcode;
52 import org.apache.derby.iapi.util.JBitSet;
53
54 import org.apache.derby.iapi.reference.SQLState;
55
56 import org.apache.derby.iapi.reference.SQLState;
57
58 import org.apache.derby.iapi.sql.Activation;
59
60 import org.apache.derby.iapi.sql.ResultColumnDescriptor;
61 import org.apache.derby.iapi.sql.Row;
62 import org.apache.derby.iapi.types.TypeId;
63
64 import org.apache.derby.iapi.sql.execute.ExecRow;
65 import org.apache.derby.iapi.sql.execute.ExecIndexRow;
66 import org.apache.derby.iapi.sql.execute.ExecutionFactory;
67 import org.apache.derby.iapi.sql.execute.ExecutionContext;
68
69 import org.apache.derby.iapi.types.DataTypeDescriptor;
70 import org.apache.derby.iapi.types.DataValueDescriptor;
71 import org.apache.derby.iapi.types.RowLocation;
72
73 import org.apache.derby.iapi.store.access.ConglomerateController;
74 import org.apache.derby.iapi.store.access.StoreCostController;
75 import org.apache.derby.iapi.store.access.TransactionController;
76
77 import org.apache.derby.iapi.services.loader.GeneratedMethod;
78
79 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
80 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
81
82 import org.apache.derby.iapi.services.io.FormatableBitSet;
83 import org.apache.derby.iapi.reference.ClassName;
84
85 import org.apache.derby.catalog.types.DefaultInfoImpl;
86
87 import java.lang.reflect.Modifier JavaDoc;
88
89 import org.apache.derby.iapi.util.ReuseFactory;
90 import org.apache.derby.iapi.services.classfile.VMOpcode;
91
92 import java.sql.ResultSetMetaData JavaDoc;
93 import java.sql.SQLException JavaDoc;
94 import java.sql.Types JavaDoc;
95
96 import java.util.Hashtable JavaDoc;
97 import java.util.Vector JavaDoc;
98
99 /**
100  * A ResultColumnList is the target list of a SELECT, INSERT, or UPDATE.
101  *
102  * @see ResultColumn
103  */

104
105 public class ResultColumnList extends QueryTreeNodeVector
106 {
107     /* Is this the ResultColumnList for an index row? */
108     protected boolean indexRow;
109     protected long conglomerateId;
110
111     int orderBySelect = 0; // the number of result columns pulled up
112
// from ORDERBY list
113
/*
114      * A comment on 'orderBySelect'. When we encounter a SELECT .. ORDER BY
115      * statement, the columns (or expressions) in the ORDER BY clause may
116      * or may not have been explicitly mentioned in the SELECT column list.
117      * If the columns were NOT explicitly mentioned in the SELECT column
118      * list, then the parsing of the ORDER BY clause implicitly generates
119      * them into the result column list, because we'll need to have those
120      * columns present at execution time in order to sort by them. Those
121      * generated columns are added to the *end* of the ResultColumnList, and
122      * we keep track of the *number* of those columns in 'orderBySelect',
123      * so we can tell whether we are looking at a generated column by seeing
124      * whether its position in the ResultColumnList is in the last
125      * 'orderBySelect' number of columns. If the SELECT .. ORDER BY
126      * statement uses the "*" token to select all the columns from a table,
127      * then during ORDER BY parsing we redundantly generate the columns
128      * mentioned in the ORDER BY clause into the ResultColumnlist, but then
129      * later in getOrderByColumn we determine that these are duplicates and
130      * we take them back out again.
131      */

132
133     /*
134     ** Is this ResultColumnList for a FromBaseTable for an index
135     ** that is to be updated?
136     */

137     protected boolean forUpdate;
138
139     // Is a count mismatch allowed - see set/get methods for details.
140
private boolean countMismatchAllowed;
141
142     // Number of RCs in this RCL at "init" time, before additional
143
// ones were added internally.
144
private int initialListSize = 0;
145
146     public ResultColumnList()
147     {
148     }
149
150     /**
151      * Add a ResultColumn (at this point, ResultColumn or
152      * AllResultColumn) to the list
153      *
154      * @param resultColumn The ResultColumn to add to the list
155      */

156
157     public void addResultColumn(ResultColumn resultColumn)
158     {
159         /* Vectors are 0-based, ResultColumns are 1-based */
160         resultColumn.setVirtualColumnId(size() + 1);
161         addElement(resultColumn);
162     }
163
164     /**
165      * Append a given ResultColumnList to this one, resetting the virtual
166      * column ids in the appended portion.
167      *
168      * @param resultColumns The ResultColumnList to be appended
169      * @param destructiveCopy Whether or not this is a descructive copy
170      * from resultColumns
171      */

172     public void appendResultColumns(ResultColumnList resultColumns,
173                                     boolean destructiveCopy)
174     {
175         int oldSize = size();
176         int newID = oldSize + 1;
177
178         /*
179         ** Set the virtual column ids in the list being appended.
180         ** Vectors are zero-based, and virtual column ids are one-based,
181         ** so the new virtual column ids start at the original size
182         ** of this list, plus one.
183         */

184         int otherSize = resultColumns.size();
185         for (int index = 0; index < otherSize; index++)
186         {
187             /* ResultColumns are 1-based */
188             ((ResultColumn) resultColumns.elementAt(index)).setVirtualColumnId(newID);
189             newID++;
190         }
191
192         if (destructiveCopy)
193         {
194             destructiveAppend(resultColumns);
195         }
196         else
197         {
198             nondestructiveAppend(resultColumns);
199         }
200     }
201
202     /**
203      * Get a ResultColumn from a column position (1-based) in the list
204      *
205      * @param position The ResultColumn to get from the list (1-based)
206      *
207      * @return the column at that position.
208      */

209
210     public ResultColumn getResultColumn(int position)
211     {
212         /*
213         ** First see if it falls in position x. If not,
214         ** search the whole shebang
215         */

216         if (position <= size())
217         {
218             // this wraps the cast needed,
219
// and the 0-based nature of the Vectors.
220
ResultColumn rc = (ResultColumn)elementAt(position-1);
221             if (rc.getColumnPosition() == position)
222             {
223                 return rc;
224             }
225         }
226         
227         /*
228         ** Check each column
229         */

230         int size = size();
231         for (int index = 0; index < size; index++)
232         {
233             ResultColumn rc = (ResultColumn) elementAt(index);
234             if (rc.getColumnPosition() == position)
235             {
236                 return rc;
237             }
238         }
239         return null;
240     }
241
242     /**
243      * Take a column position and a ResultSetNode and find the ResultColumn
244      * in this RCL whose source result set is the same as the received
245      * RSN and whose column position is the same as the received column
246      * position.
247      *
248      * @param colNum The column position (w.r.t rsn) for which we're searching
249      * @param rsn The result set node for which we're searching.
250      * @return The ResultColumn in this RCL whose source is column colNum
251      * in result set rsn. That ResultColumn's position w.r.t to this RCL
252      * is also returned via the whichRC parameter. If no match is found,
253      * return null and leave whichRC untouched.
254      */

255     public ResultColumn getResultColumn(int colNum, ResultSetNode rsn,
256         int [] whichRC) throws StandardException
257     {
258         if (colNum == -1)
259             return null;
260
261         ResultColumn rc = null;
262         ColumnReference colRef = null;
263         int [] crColNum = new int[] { -1 };
264
265         for (int index = size() - 1; index >= 0; index--)
266         {
267             rc = (ResultColumn) elementAt(index);
268             if (!(rc.getExpression() instanceof ColumnReference))
269             {
270                 // If the rc's expression isn't a column reference then
271
// it can't be pointing to rsn, so just skip it.
272
continue;
273             }
274
275             colRef = (ColumnReference)rc.getExpression();
276             if ((rsn == colRef.getSourceResultSet(crColNum)) &&
277                 (crColNum[0] == colNum))
278             {
279                 // Found a match.
280
whichRC[0] = index+1;
281                 return rc;
282             }
283         }
284
285         return null;
286     }
287
288     /**
289      * Get a ResultColumn from a column position (1-based) in the list,
290      * null if out of range (for order by).
291      *
292      * @param position The ResultColumn to get from the list (1-based)
293      *
294      * @return the column at that position, null if out of range
295      */

296     public ResultColumn getOrderByColumn(int position)
297     {
298         // this wraps the cast needed, and the 0-based nature of the Vectors.
299
if (position == 0)
300             return null;
301
302         return getResultColumn(position);
303     }
304
305     /**
306      * Get a ResultColumn that matches the specified columnName and
307      * mark the ResultColumn as being referenced.
308      *
309      * @param columnName The ResultColumn to get from the list
310      *
311      * @return the column that matches that name.
312      */

313
314     public ResultColumn getResultColumn(String JavaDoc columnName)
315     {
316         int size = size();
317         for (int index = 0; index < size; index++)
318         {
319             ResultColumn resultColumn = (ResultColumn) elementAt(index);
320             if (columnName.equals( resultColumn.getName()) )
321             {
322                 /* Mark ResultColumn as referenced and return it */
323                 resultColumn.setReferenced();
324                 return resultColumn;
325             }
326         }
327         return null;
328     }
329
330     /**
331      * Get a ResultColumn that matches the specified columnName and
332      * mark the ResultColumn as being referenced.
333      *
334      * @param columnsTableName Qualifying name for the column
335      * @param columnName The ResultColumn to get from the list
336      *
337      * @return the column that matches that name.
338      */

339
340     public ResultColumn getResultColumn(String JavaDoc columnsTableName, String JavaDoc columnName)
341     {
342         int size = size();
343         for (int index = 0; index < size; index++)
344         {
345             ResultColumn resultColumn = (ResultColumn) elementAt(index);
346
347             /* If the column's table name is non-null, then we have found a match
348              * only if the RC's table name is non-null and the same as the
349              * the CR's table name.
350              */

351             if (columnsTableName != null)
352             {
353                 if (resultColumn.getTableName() == null)
354                 {
355                     continue;
356                 }
357                 
358                 if (! columnsTableName.equals(resultColumn.getTableName()))
359                 {
360                     continue;
361                 }
362             }
363             if (columnName.equals( resultColumn.getName()) )
364             {
365                 /* Mark ResultColumn as referenced and return it */
366                 resultColumn.setReferenced();
367                 return resultColumn;
368             }
369         }
370         return null;
371     }
372
373     /**
374      * Get a ResultColumn that matches the specified columnName and
375      * mark the ResultColumn as being referenced.
376      * NOTE - this flavor enforces no ambiguity (at most 1 match)
377      * Only FromSubquery needs to call this flavor since
378      * it can have ambiguous references in its own list.
379      *
380      * @param cr The ColumnReference to resolve
381      * @param exposedTableName Exposed table name for FromTable
382      *
383      * @return the column that matches that name.
384      *
385      * @exception StandardException Thrown on error
386      */

387
388     public ResultColumn getAtMostOneResultColumn(
389                                 ColumnReference cr,
390                                 String JavaDoc exposedTableName)
391         throws StandardException
392     {
393         int size = size();
394         ResultColumn retRC = null;
395         String JavaDoc columnName = cr.getColumnName();
396
397         for (int index = 0; index < size; index++)
398         {
399             ResultColumn resultColumn = (ResultColumn) elementAt(index);
400
401             if (columnName.equals( resultColumn.getName()) )
402             {
403                 /* We should get at most 1 match */
404                 if (retRC != null)
405                 {
406                     throw StandardException.newException(SQLState.LANG_AMBIGUOUS_COLUMN_NAME_IN_TABLE,
407                              columnName, exposedTableName);
408                 }
409                 /* Mark ResultColumn as referenced and return it */
410                 resultColumn.setReferenced();
411                 retRC = resultColumn;
412             }
413         }
414         return retRC;
415     }
416
417     /**
418      * For order by, get a ResultColumn that matches the specified
419      * columnName.
420      *
421      * @param columnName The ResultColumn to get from the list
422      * @param tableName The table name on the OrderByColumn, if any
423      * @param tableNumber The tableNumber corresponding to the FromTable with the
424      * exposed name of tableName, if tableName != null.
425      *
426      * @return the column that matches that name.
427      * @exception StandardException thrown on ambiguity
428      */

429     public ResultColumn getOrderByColumn(String JavaDoc columnName, TableName tableName, int tableNumber)
430         throws StandardException
431     {
432         int size = size();
433         ResultColumn retVal = null, resultColumn;
434
435         for (int index = 0; index < size; index++)
436         {
437             resultColumn = (ResultColumn) elementAt(index);
438
439             /* The order by column is qualified, then it is okay to consider
440              * this RC if:
441              * o The RC is qualified and the qualifiers on the order by column
442              * and the RC are equal().
443              * o The RC is not qualified, but its expression is a ColumnReference
444              * from the same table (as determined by the tableNumbers).
445              */

446             if (tableName != null)
447             {
448                 ValueNode rcExpr = resultColumn.getExpression();
449                 if (! (rcExpr instanceof ColumnReference))
450                         continue;
451
452                 ColumnReference cr = (ColumnReference) rcExpr;
453                 if( (! tableName.equals( cr.getTableNameNode())) && tableNumber != cr.getTableNumber())
454                     continue;
455             }
456
457             /* We finally got past the qualifiers, now see if the column
458              * names are equal. If they are, then we appear to have found
459             * our order by column. If we find our order by column multiple
460             * times, make sure that they are truly duplicates, otherwise
461             * we have an ambiguous situation. For example, the query
462             * SELECT b+c AS a, d+e AS a FROM t ORDER BY a
463             * is ambiguous because we don't know which "a" is meant. But
464             * SELECT t.a, t.* FROM t ORDER BY a
465             * is not ambiguous, even though column "a" is selected twice.
466             * If we find our ORDER BY column at the end of the
467             * SELECT column list, in the last 'orderBySelect' number
468             * of columns, then this column was not explicitly mentioned
469             * by the user in their SELECT column list, but was implicitly
470             * added by the parsing of the ORDER BY clause, and it
471             * should be removed from the ResultColumnList and returned
472             * to the caller.
473              */

474             if (columnName.equals( resultColumn.getName()) )
475             {
476                 if (retVal == null)
477                 {
478                     retVal = resultColumn;
479                 }
480                 else if (! retVal.isEquivalent(resultColumn))
481                 {
482                     throw StandardException.newException(SQLState.LANG_DUPLICATE_COLUMN_FOR_ORDER_BY, columnName);
483                 }
484                 else if (index >= size - orderBySelect)
485                 {// remove the column due to pullup of orderby item
486
removeElement(resultColumn);
487                     decOrderBySelect();
488                     break;
489                 }
490             }
491         }
492         return retVal;
493     }
494
495
496     /**
497      * For order by, get a ResultColumn that matches the specified
498      * columnName.
499      *
500      * @param columnName The ResultColumn to get from the list
501      * @param tableName The table name on the OrderByColumn, if any
502      *
503      * @return the column that matches that name.
504      * @exception StandardException thrown on ambiguity
505      */

506     public ResultColumn getOrderByColumn(String JavaDoc columnName, TableName tableName)
507         throws StandardException
508     {
509         int size = size();
510         ResultColumn retVal = null, resultColumn;
511
512         for (int index = 0; index < size; index++)
513         {
514             resultColumn = (ResultColumn) elementAt(index);
515
516             // We may be checking on "ORDER BY T.A" against "SELECT *".
517
// exposedName will not be null and "*" will not have an expression
518
// or tablename.
519
// We may be checking on "ORDER BY T.A" against "SELECT T.B, T.A".
520
if (tableName != null)
521             {
522                 ValueNode rcExpr = resultColumn.getExpression();
523                 if (rcExpr == null || ! (rcExpr instanceof ColumnReference))
524                 {
525                     continue;
526                 }
527                 ColumnReference cr = (ColumnReference) rcExpr;
528                 if( ! tableName.equals( cr.getTableNameNode()))
529                     continue;
530             }
531
532             /* We finally got past the qualifiers, now see if the column
533              * names are equal.
534              */

535             if (columnName.equals( resultColumn.getName()) )
536             {
537                 if (retVal == null)
538                 {
539                     retVal = resultColumn;
540                 }
541                 else if (! retVal.isEquivalent(resultColumn))
542                 {
543                     throw StandardException.newException(SQLState.LANG_DUPLICATE_COLUMN_FOR_ORDER_BY, columnName);
544                 }
545                 else if (index >= size - orderBySelect)
546                 {// remove the column due to pullup of orderby item
547
removeElement(resultColumn);
548                     decOrderBySelect();
549                     break;
550                 }
551             }
552         }
553         return retVal;
554     }
555
556
557     /**
558      * Copy the result column names from the given ResultColumnList
559      * to this ResultColumnList. This is useful for insert-select,
560      * where the columns being inserted into may be different from
561      * the columns being selected from. The result column list for
562      * an insert is supposed to have the column names being inserted
563      * into.
564      *
565      * @param nameList The ResultColumnList from which to copy
566      * the column names
567      */

568
569     void copyResultColumnNames(ResultColumnList nameList)
570     {
571         /* List checking is done during bind(). Lists should be the
572          * same size when we are called.
573          */

574         if (SanityManager.DEBUG)
575         {
576              if ((! countMismatchAllowed) && size() != nameList.size())
577              {
578                 SanityManager.THROWASSERT(
579                     "The size of the 2 lists is expected to be the same. size() = " +
580                     size() + ", nameList.size() = " + nameList.size());
581              }
582          }
583
584         int size = (countMismatchAllowed) ? nameList.size() : size();
585         for (int index = 0; index < size; index++)
586         {
587             ResultColumn thisResultColumn = (ResultColumn) elementAt(index);
588             ResultColumn nameListResultColumn =
589                 (ResultColumn) nameList.elementAt(index);
590             thisResultColumn.setName(nameListResultColumn.getName());
591             thisResultColumn.setNameGenerated(nameListResultColumn.isNameGenerated());
592         }
593     }
594
595     /**
596      * This class needs a treePrint method, even though it is not a
597      * descendant of QueryTreeNode, because its members contain tree
598      * nodes, and these have to be printed and indented properly.
599      *
600      * @param depth The depth at which to indent the sub-nodes
601      */

602
603     public void treePrint(int depth)
604     {
605         if (SanityManager.DEBUG)
606         {
607             for (int index = 0; index < size(); index++)
608             {
609                 ((ResultColumn) elementAt(index) ).treePrint(depth);
610             }
611         }
612     }
613
614     /**
615      * Bind the expressions in this ResultColumnList. This means binding
616      * the expression under each ResultColumn node.
617      *
618      * @param fromList The FROM list for the query this
619      * expression is in, for binding columns.
620      * @param subqueryList The subquery list being built as we find SubqueryNodes
621      * @param aggregateVector The aggregate vector being built as we find AggregateNodes
622      *
623      * @exception StandardException Thrown on error
624      */

625     public void bindExpressions(
626                     FromList fromList, SubqueryList subqueryList,
627                     Vector JavaDoc aggregateVector)
628                 throws StandardException
629     {
630         /* First we expand the *'s in the result column list */
631         expandAllsAndNameColumns(fromList);
632
633         /* Now we bind each result column */
634         int size = size();
635         for (int index = 0; index < size; index++)
636         {
637             ValueNode vn = (ValueNode) elementAt(index);
638             vn = ((ResultColumn) vn ).bindExpression(
639                                                 fromList, subqueryList,
640                                                 aggregateVector);
641             setElementAt(vn, index);
642         }
643     }
644
645     /**
646      * Bind the result columns to the expressions that live under them.
647      * All this does is copy the datatype information to from each expression
648      * to each result column. This is useful for SELECT statements, where
649      * the result type of each column is the type of the column's expression.
650      *
651      * @exception StandardException Thrown on error
652      */

653     public void bindResultColumnsToExpressions()
654                     throws StandardException
655     {
656         int size = size();
657         for (int index = 0; index < size; index++)
658         {
659             ((ResultColumn) elementAt(index) ).bindResultColumnToExpression();
660         }
661     }
662
663     /**
664      * Bind the result columns by their names. This is useful for GRANT and REVOKE statements
665      * like "GRANT SELECT ON t(c1,c1,c3) TO george", where the user specified a column list.
666      * This method does not check for duplicate column names.
667      *
668      * @param targetTableDescriptor The descriptor for the table
669      *
670      * @exception StandardException Thrown on error
671      */

672     public void bindResultColumnsByName(TableDescriptor targetTableDescriptor)
673                     throws StandardException
674     {
675         int size = size();
676
677         for (int index = 0; index < size; index++)
678         {
679             ResultColumn rc = (ResultColumn) elementAt(index);
680
681             rc.bindResultColumnByName(
682                         targetTableDescriptor,
683                         index + 1
684                     );
685         }
686     } // end of bindResultColumnsByName( TableDescriptor)
687

688     /**
689      * Bind the result columns by their names. This is useful for update, grant, and revoke
690      * statements, and for INSERT statements like "insert into t (a, b, c)
691      * values (1, 2, 3)" where the user specified a column list.
692      * If the statment is an insert or update verify that the result column list does not contain any duplicates.
693      * NOTE: We pass the ResultColumns position in the ResultColumnList so
694      * that the VirtualColumnId gets set.
695      *
696      * @param targetTableDescriptor The descriptor for the table being
697      * updated or inserted into
698      * @param statement DMLStatementNode containing this list, null if no duplicate checking is to be done
699      *
700      * @return A FormatableBitSet representing the set of columns with respect to the table
701      *
702      * @exception StandardException Thrown on error
703      */

704     public FormatableBitSet bindResultColumnsByName(TableDescriptor targetTableDescriptor,
705                                                     DMLStatementNode statement)
706                     throws StandardException
707     {
708         int size = size();
709         FormatableBitSet columnBitSet = new FormatableBitSet( targetTableDescriptor.getNumberOfColumns());
710
711         for (int index = 0; index < size; index++)
712         {
713             ResultColumn rc = (ResultColumn) elementAt(index);
714
715             rc.bindResultColumnByName(
716                         targetTableDescriptor,
717                         index + 1
718                     );
719             int colIdx = rc.getColumnPosition() - 1;
720             if( SanityManager.DEBUG)
721                 SanityManager.ASSERT( colIdx >= 0 && colIdx < targetTableDescriptor.getNumberOfColumns(),
722                                       "Invalid column position found for " + rc.getName());
723             /* Verify that this column's name is unique within the list if requested */
724             if( statement != null && columnBitSet.isSet( colIdx))
725             {
726                 String JavaDoc colName = rc.getName();
727
728                 if (statement instanceof UpdateNode)
729                 {
730                     throw StandardException.newException(SQLState.LANG_DUPLICATE_COLUMN_NAME_UPDATE, colName);
731                 }
732                 else
733                 {
734                     throw StandardException.newException(SQLState.LANG_DUPLICATE_COLUMN_NAME_INSERT, colName);
735                 }
736             }
737             columnBitSet.set( colIdx);
738         }
739         return columnBitSet;
740     }
741
742     /**
743      * Bind the result columns by their names. This is useful for update
744      * VTI statements, and for INSERT statements like "insert into new t() (a, b, c)
745      * values (1, 2, 3)" where the user specified a column list.
746      * Also, verify that the result column list does not contain any duplicates.
747      * NOTE: We pass the ResultColumns position in the ResultColumnList so
748      * that the VirtualColumnId gets set.
749      *
750      * @param fullRCL The full RCL for the target table
751      * @param statement DMLStatementNode containing this list
752      *
753      * @exception StandardException Thrown on error
754      */

755     public void bindResultColumnsByName(ResultColumnList fullRCL,
756                                         FromVTI targetVTI,
757                                         DMLStatementNode statement)
758                     throws StandardException
759     {
760         int size = size();
761         Hashtable JavaDoc ht = new Hashtable JavaDoc(size + 2, (float) .999);
762
763         for (int index = 0; index < size; index++)
764         {
765             ResultColumn matchRC;
766             ResultColumn rc = (ResultColumn) elementAt(index);
767
768             /* Verify that this column's name is unique within the list */
769             String JavaDoc colName = rc.getName();
770
771             Object JavaDoc object = ht.put(colName, colName);
772
773             if (object != null &&
774                 ((String JavaDoc) object).equals(colName))
775             {
776                 if (SanityManager.DEBUG)
777                 {
778                     SanityManager.ASSERT((statement instanceof UpdateNode) ||
779                                          (statement instanceof InsertNode),
780                         "statement is expected to be instanceof UpdateNode or InsertNode");
781                 }
782                 if (statement instanceof UpdateNode)
783                 {
784                     throw StandardException.newException(SQLState.LANG_DUPLICATE_COLUMN_NAME_UPDATE, colName);
785                 }
786                 else
787                 {
788                     throw StandardException.newException(SQLState.LANG_DUPLICATE_COLUMN_NAME_INSERT, colName);
789                 }
790             }
791
792             matchRC = fullRCL.getResultColumn(null, rc.getName());
793             if (matchRC == null)
794             {
795                 throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE,
796                                                      rc.getName(),
797                                                      targetVTI.getNewInvocation().getJavaClassName());
798             }
799
800             /* We have a match. We need to create a dummy ColumnDescriptor
801              * since calling code expects one to get column info.
802              */

803             ColumnDescriptor cd = new ColumnDescriptor(
804                                             rc.getName(),
805                                             matchRC.getVirtualColumnId(),
806                                             matchRC.getType(),
807                                             null,
808                                             null,
809                                             (TableDescriptor) null,
810                                             null,
811                                             0, 0);
812             rc.setColumnDescriptor(null, cd);
813             rc.setVirtualColumnId(index + 1);
814         }
815     }
816
817     /**
818      * Bind the result columns by ordinal position. This is useful for
819      * INSERT statements like "insert into t values (1, 2, 3)", where the
820      * user did not specify a column list.
821      *
822      * @param targetTableDescriptor The descriptor for the table being
823      * inserted into
824      *
825      * @exception StandardException Thrown on error
826      */

827     public void bindResultColumnsByPosition(TableDescriptor targetTableDescriptor)
828                     throws StandardException
829     {
830         int size = size();
831
832         for (int index = 0; index < size; index++)
833         {
834             /*
835             ** Add one to the iterator index, because iterator indexes start at zero,
836             ** and column numbers start at one.
837             */

838             ((ResultColumn) elementAt(index) ).bindResultColumnByPosition(
839                         targetTableDescriptor,
840                         index + 1);
841         }
842     }
843
844     /**
845      * Preprocess the expression trees under the RCL.
846      * We do a number of transformations
847      * here (including subqueries, IN lists, LIKE and BETWEEN) plus
848      * subquery flattening.
849      * NOTE: This is done before the outer ResultSetNode is preprocessed.
850      *
851      * @param numTables Number of tables in the DML Statement
852      * @param outerFromList FromList from outer query block
853      * @param outerSubqueryList SubqueryList from outer query block
854      * @param outerPredicateList PredicateList from outer query block
855      *
856      * @exception StandardException Thrown on error
857      */

858     public void preprocess(int numTables,
859                             FromList outerFromList,
860                             SubqueryList outerSubqueryList,
861                             PredicateList outerPredicateList)
862                     throws StandardException
863     {
864         int size = size();
865
866         for (int index = 0; index < size; index++)
867         {
868             ResultColumn resultColumn = (ResultColumn) elementAt(index);
869             setElementAt(resultColumn.preprocess(numTables,
870                                                  outerFromList,
871                                                  outerSubqueryList,
872                                                  outerPredicateList),
873                          index);
874         }
875     }
876
877     /**
878         Verify that all the result columns have expressions that
879         are storable for them. Check versus the given ResultColumnList.
880
881         @exception StandardException Thrown on error
882      */

883     void checkStorableExpressions(ResultColumnList toStore)
884             throws StandardException
885     {
886         int size = size();
887
888         for (int index = 0; index < size; index++)
889         {
890             ResultColumn otherRC = (ResultColumn) toStore.elementAt(index);
891
892             ((ResultColumn) elementAt(index) ).checkStorableExpression(otherRC);
893         }
894     }
895
896     /**
897       Return an array holding the 0 based heap offsets of
898       the StreamStorable columns in this ResultColumnList.
899       This returns null if this list does not contain any
900       StreamStorableColumns. The list this returns does not
901       contain duplicates. This should only be used for
902       a resultColumnList the refers to a single heap
903       such as the target for an Insert, Update or Delete.
904       @param heapColCount the number of heap columns
905       @exception StandardException Thrown on error
906      */

907     public int[] getStreamStorableColIds(int heapColCount) throws StandardException
908     {
909         //@#$
910
//System.out.println("getStreamStorableColids");
911

912         int ssCount = 0;
913         boolean[] isSS = new boolean[heapColCount];//Should be table length.
914
int size = size();
915
916         for (int index = 0; index < size; index++)
917         {
918             ResultColumn rc = (ResultColumn) elementAt(index);
919
920             if (rc.getTypeId().streamStorable())
921             {
922                 //System.out.println(" streamStorable=true");
923
ColumnDescriptor cd = rc.getTableColumnDescriptor();
924                 isSS[cd.getPosition()-1] = true;
925             }
926         }
927
928         for (int ix=0;ix<isSS.length;ix++) if (isSS[ix]) ssCount++;
929
930         if (ssCount==0)return null;
931
932         int[] result = new int[ssCount];
933         int resultOffset=0;
934         for (int heapOffset=0;heapOffset<isSS.length;heapOffset++)
935         {
936             if (isSS[heapOffset])
937                 result[resultOffset++]=heapOffset;
938         }
939
940         return result;
941     }
942     
943     /**
944         Verify that all the result columns have expressions that
945         are storable for them. Check versus the expressions under the
946         ResultColumns.
947
948         @exception StandardException Thrown on error
949      */

950     void checkStorableExpressions()
951             throws StandardException
952     {
953         int size = size();
954
955         for (int index = 0; index < size; index++)
956         {
957             ((ResultColumn) elementAt(index) ).checkStorableExpression();
958         }
959     }
960
961
962     /**
963      * Generate the code to place the columns' values into
964      * a row variable named "r". This wrapper is here
965      * rather than in ResultColumn, because that class does
966      * not know about the position of the columns in the list.
967      *
968      * @exception StandardException Thrown on error
969      */

970     public void generate(ActivationClassBuilder acb, MethodBuilder mb)
971             throws StandardException
972     {
973         generateCore(acb, mb, false);
974     }
975
976     /**
977      * Generate the code to place the columns' values into
978      * a row variable named "r". This wrapper is here
979      * rather than in ResultColumn, because that class does
980      * not know about the position of the columns in the list.
981      *
982      * @exception StandardException Thrown on error
983      */

984     void generateNulls(ActivationClassBuilder acb,
985                             MethodBuilder mb)
986             throws StandardException
987     {
988         generateCore(acb, mb, true);
989     }
990
991     /**
992      * Generate the code to place the columns' values into
993      * a row variable named "r". This wrapper is here
994      * rather than in ResultColumn, because that class does
995      * not know about the position of the columns in the list.
996      *
997      * This is the method that does the work.
998      */

999     void generateCore(ExpressionClassBuilder acb,
1000                            MethodBuilder mb,
1001                            boolean genNulls)
1002            throws StandardException
1003    {
1004        // generate the function and initializer:
1005
// private ExecRow fieldX;
1006
// In the constructor:
1007
// fieldX = getExecutionFactory().getValueRow(# cols);
1008
// private ExecRow exprN()
1009
// {
1010
// fieldX.setColumn(1, col(1).generateColumn(ps)));
1011
// ... and so on for each column ...
1012
// return fieldX;
1013
// }
1014
// static Method exprN = method pointer to exprN;
1015

1016        // this sets up the method and the static field.
1017
MethodBuilder userExprFun = acb.newUserExprFun();
1018
1019        /* Declare the field */
1020        LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.ExecRow);
1021
1022        // Generate the code to create the row in the constructor
1023
genCreateRow(acb, field, "getValueRow", ClassName.ExecRow, size());
1024
1025        ResultColumn rc;
1026        int size = size();
1027
1028        MethodBuilder cb = acb.getConstructor();
1029
1030        for (int index = 0; index < size; index++)
1031        {
1032            // generate statements of the form
1033
// fieldX.setColumn(columnNumber, (DataValueDescriptor) columnExpr);
1034
// and add them to exprFun.
1035
rc = (ResultColumn) elementAt(index);
1036
1037            /* If we are not generating nulls, then we can skip this RC if
1038             * it is simply propagating a column from the source result set.
1039             */

1040            if (!genNulls)
1041            {
1042                ValueNode sourceExpr = rc.getExpression();
1043
1044                if (sourceExpr instanceof VirtualColumnNode && ! ( ((VirtualColumnNode) sourceExpr).getCorrelated()))
1045                {
1046                    continue;
1047                }
1048
1049                if (sourceExpr instanceof ColumnReference && ! ( ((ColumnReference) sourceExpr).getCorrelated()))
1050                {
1051                    continue;
1052                }
1053            }
1054
1055
1056            // row add is 1-based, and iterator index is 0-based
1057
if (SanityManager.DEBUG)
1058            {
1059                if (index + 1 != rc.getVirtualColumnId())
1060                {
1061                    SanityManager.THROWASSERT(
1062                        "VirtualColumnId (" +
1063                        rc.getVirtualColumnId() +
1064                        ") does not agree with position within Vector (" +
1065                        (index + 1) +
1066                        ")");
1067                }
1068            }
1069
1070            // we need the expressions to be Columns exactly.
1071

1072            /* SPECIAL CASE: Expression is a non-null constant.
1073             * Generate the setColumn() call in the constructor
1074             * so that it will only be executed once per instantiation.
1075             *
1076             * Increase the statement counter in constructor. Code size in
1077             * constructor can become too big (more than 64K) for Java compiler
1078             * to handle (beetle 4293). We set constant columns in other
1079             * methods if constructor has too many statements already.
1080             */

1081            if ( (! genNulls) &&
1082                 (rc.getExpression() instanceof ConstantNode) &&
1083                 ! ((ConstantNode) rc.getExpression()).isNull() &&
1084                 ! cb.statementNumHitLimit(1))
1085            {
1086
1087
1088                cb.getField(field); // instance
1089
cb.push(index + 1); // first arg;
1090

1091                rc.generateExpression(acb, cb);
1092                cb.cast(ClassName.DataValueDescriptor); // second arg
1093
cb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "setColumn", "void", 2);
1094                continue;
1095            }
1096
1097            userExprFun.getField(field); // instance
1098
userExprFun.push(index + 1); // arg1
1099

1100            /* We want to reuse the null values instead of doing a new each time
1101             * if the caller said to generate nulls or the underlying expression
1102             * is a typed null value.
1103             */

1104            boolean needDVDCast = true;
1105            if (rc.isAutoincrementGenerated())
1106            {
1107                // (com.ibm.db2j.impl... DataValueDescriptor)
1108
// this.getSetAutoincValue(column_number)
1109

1110                userExprFun.pushThis();
1111
1112                userExprFun.push(rc.getColumnPosition());
1113                userExprFun.push(rc.getTableColumnDescriptor().getAutoincInc());
1114
1115                userExprFun.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation,
1116                        "getSetAutoincrementValue", ClassName.DataValueDescriptor, 2);
1117                needDVDCast = false;
1118                
1119            }
1120            else if (genNulls ||
1121                ((rc.getExpression() instanceof ConstantNode) &&
1122                 ((ConstantNode) rc.getExpression()).isNull()))
1123            {
1124                userExprFun.getField(field);
1125                userExprFun.push(index + 1);
1126                userExprFun.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "getColumn",
1127                    ClassName.DataValueDescriptor, 1); // the express
1128

1129                acb.generateNullWithExpress(userExprFun, rc.getTypeCompiler());
1130
1131            }
1132            else
1133            {
1134                rc.generateExpression(acb, userExprFun);
1135            }
1136            if (needDVDCast)
1137                userExprFun.cast(ClassName.DataValueDescriptor);
1138
1139            userExprFun.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "setColumn", "void", 2);
1140        }
1141        userExprFun.getField(field);
1142        userExprFun.methodReturn();
1143
1144        // we are now done modifying userExprFun
1145
userExprFun.complete();
1146
1147        // what we return is the access of the field, i.e. the pointer to the method.
1148
acb.pushMethodReference(mb, userExprFun);
1149    }
1150
1151    /**
1152      * Build an empty row with the size and shape of the ResultColumnList.
1153      *
1154      * @return an empty row of the correct size and shape.
1155      * @exception StandardException Thrown on error
1156     */

1157    public ExecRow buildEmptyRow()
1158        throws StandardException
1159    {
1160        int columnCount = size();
1161        ExecRow row = getExecutionFactory().getValueRow( columnCount );
1162        int position = 1;
1163
1164        for (int index = 0; index < columnCount; index++)
1165        {
1166            ResultColumn rc = (ResultColumn) elementAt(index);
1167            DataTypeDescriptor dataType = rc.getTypeServices();
1168            DataValueDescriptor dataValue = dataType.getNull();
1169
1170            row.setColumn( position++, dataValue );
1171        }
1172
1173        return row;
1174    }
1175
1176    /**
1177      * Build an empty index row for the given conglomerate.
1178      *
1179      * @return an empty row of the correct size and shape.
1180      * @exception StandardException Thrown on error
1181     */

1182    public ExecRow buildEmptyIndexRow(TableDescriptor td,
1183                                        ConglomerateDescriptor cd,
1184                                        StoreCostController scc,
1185                                        DataDictionary dd)
1186        throws StandardException
1187    {
1188        ResultColumn rc;
1189
1190        if (SanityManager.DEBUG)
1191        {
1192            if (! cd.isIndex())
1193            {
1194                SanityManager.THROWASSERT("ConglomerateDescriptor expected to be for index: " + cd);
1195            }
1196        }
1197
1198        int[] baseCols = cd.getIndexDescriptor().baseColumnPositions();
1199        ExecRow row = getExecutionFactory().getValueRow(baseCols.length + 1);
1200
1201        for (int i = 0; i < baseCols.length; i++)
1202        {
1203            ColumnDescriptor coldes = td.getColumnDescriptor(baseCols[i]);
1204            DataTypeDescriptor dataType = coldes.getType();
1205
1206            // rc = getResultColumn(baseCols[i]);
1207
// rc = (ResultColumn) at(baseCols[i] - 1);
1208
// dataType = rc.getTypeServices();
1209
DataValueDescriptor dataValue = dataType.getNull();
1210
1211            row.setColumn(i + 1, dataValue );
1212        }
1213
1214        RowLocation rlTemplate = scc.newRowLocationTemplate();
1215
1216        row.setColumn(baseCols.length + 1, rlTemplate);
1217
1218        return row;
1219    }
1220
1221
1222    /**
1223        Generates a row with the size and shape of the ResultColumnList.
1224
1225        Some structures, like FromBaseTable and DistinctNode,
1226        need to generate rowAllocator functions to get a row
1227        the size and shape of their ResultColumnList.
1228
1229        We return the method pointer, which is a field access
1230        in the generated class.
1231
1232        @exception StandardException
1233     */

1234    void generateHolder(ExpressionClassBuilder acb,
1235                                MethodBuilder mb)
1236                            throws StandardException
1237    {
1238        generateHolder(acb, mb, (FormatableBitSet) null, (FormatableBitSet) null);
1239    }
1240
1241    /**
1242        Generates a row with the size and shape of the ResultColumnList.
1243
1244        Some structures, like FromBaseTable and DistinctNode,
1245        need to generate rowAllocator functions to get a row
1246        the size and shape of their ResultColumnList.
1247
1248        We return the method pointer, which is a field access
1249        in the generated class.
1250
1251        @exception StandardException
1252     */

1253    void generateHolder(ExpressionClassBuilder acb,
1254                                MethodBuilder mb,
1255                                FormatableBitSet referencedCols,
1256                                FormatableBitSet propagatedCols)
1257                                throws StandardException {
1258
1259        // what we return is a pointer to the method.
1260
acb.pushMethodReference(mb, generateHolderMethod(acb, referencedCols, propagatedCols));
1261    }
1262
1263    MethodBuilder generateHolderMethod(ExpressionClassBuilder acb,
1264                                FormatableBitSet referencedCols,
1265                                FormatableBitSet propagatedCols)
1266                            throws StandardException {
1267        int numCols;
1268        String JavaDoc rowAllocatorMethod;
1269        String JavaDoc rowAllocatorType;
1270        int highestColumnNumber = -1;
1271
1272        if (referencedCols != null)
1273        {
1274            // Find the number of the last column referenced in the table
1275
for (int i = referencedCols.anySetBit();
1276                 i != -1;
1277                 i = referencedCols.anySetBit(i))
1278            {
1279                highestColumnNumber = i;
1280            }
1281        }
1282        else
1283        {
1284            highestColumnNumber = size() - 1;
1285        }
1286
1287        // Within the constructor:
1288
// fieldX = getExecutionFactory().getValueRow(# cols);
1289
// The body of the new method:
1290
// {
1291
// fieldX.setColumn(1, col(1).generateColumn(ps)));
1292
// ... and so on for each column ...
1293
// return fieldX;
1294
// }
1295
// static Method exprN = method pointer to exprN;
1296

1297        // this sets up the method and the static field
1298
MethodBuilder exprFun = acb.newExprFun();
1299
1300        // Allocate the right type of row, depending on
1301
// whether we're scanning an index or a heap.
1302
if (indexRow)
1303        {
1304            rowAllocatorMethod = "getIndexableRow";
1305            rowAllocatorType = ClassName.ExecIndexRow;
1306        }
1307        else
1308        {
1309            rowAllocatorMethod = "getValueRow";
1310            rowAllocatorType = ClassName.ExecRow;
1311        }
1312        numCols = size();
1313
1314        /* Declare the field */
1315        LocalField lf = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.ExecRow);
1316        // Generate the code to create the row in the constructor
1317
genCreateRow(acb, lf, rowAllocatorMethod, rowAllocatorType, highestColumnNumber + 1);
1318
1319        // now we fill in the body of the function
1320

1321        int colNum;
1322
1323        // If there is a referenced column map, the first column to fill
1324
// in is the first one in the bit map - otherwise, it is
1325
// column 0.
1326
if (referencedCols != null)
1327            colNum = referencedCols.anySetBit();
1328        else
1329            colNum = 0;
1330
1331        for (int index = 0; index < numCols; index++)
1332        {
1333            ResultColumn rc = ((ResultColumn) elementAt(index));
1334
1335            /* Special code generation for RID since expression is CurrentRowLocationNode.
1336             * Really need yet another node type that does its own code generation.
1337             */

1338            if (rc.getExpression() instanceof CurrentRowLocationNode)
1339            {
1340                ConglomerateController cc = null;
1341                int savedItem;
1342                RowLocation rl;
1343                
1344                cc = getLanguageConnectionContext().
1345                        getTransactionCompile().openConglomerate(
1346                            conglomerateId,
1347                            false,
1348                            0,
1349                            TransactionController.MODE_RECORD,
1350                            TransactionController.ISOLATION_READ_COMMITTED);
1351                try
1352                {
1353                    rl = cc.newRowLocationTemplate();
1354                }
1355                finally
1356                {
1357                    if (cc != null)
1358                    {
1359                        cc.close();
1360                    }
1361                }
1362
1363                savedItem = acb.addItem(rl);
1364                                
1365                // get the RowLocation template
1366
exprFun.getField(lf); // instance for setColumn
1367
exprFun.push(highestColumnNumber + 1); // first arg
1368

1369                exprFun.pushThis(); // instance for getRowLocationTemplate
1370
exprFun.push(savedItem); // first arg
1371
exprFun.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Activation, "getRowLocationTemplate",
1372                                    ClassName.RowLocation, 1);
1373
1374                exprFun.upCast(ClassName.DataValueDescriptor);
1375                exprFun.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "setColumn",
1376                                            "void", 2);
1377                continue;
1378            }
1379
1380            /* Skip over those columns whose source is the immediate
1381             * child result set. (No need to generate a wrapper
1382             * for a SQL NULL when we are smart enough not to pass
1383             * that wrapper to the store.)
1384             * NOTE: Believe it or not, we have to check for the case
1385             * where referencedCols is not null, but no bits are set.
1386             * This can happen when we need to get all of the columns
1387             * from the heap due to a check constraint.
1388             */

1389            if (propagatedCols != null &&
1390                propagatedCols.getNumBitsSet() != 0)
1391            {
1392                /* We can skip this RC if it is simply propagating
1393                 * a column from the source result set.
1394                 */

1395                ValueNode sourceExpr = rc.getExpression();
1396
1397                if (sourceExpr instanceof VirtualColumnNode)
1398                {
1399                    // There is a referenced columns bit set, so use
1400
// it to figure out what the next column number is.
1401
// colNum = referencedCols.anySetBit(colNum);
1402
continue;
1403                }
1404            }
1405
1406            // generate the column space creation call
1407
// generate statements of the form
1408
// r.setColumn(columnNumber, columnShape);
1409
//
1410
// This assumes that there are no "holes" in the column positions,
1411
// and that column positions reflect the stored format/order
1412
exprFun.getField(lf); // instance
1413
exprFun.push(colNum + 1); // first arg
1414
rc.generateHolder(acb, exprFun);
1415
1416            exprFun.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "setColumn", "void", 2);
1417
1418            // If there is a bit map of referenced columns, use it to
1419
// figure out what the next column is, otherwise just go
1420
// to the next column.
1421
if (referencedCols != null)
1422                colNum = referencedCols.anySetBit(colNum);
1423            else
1424                colNum++;
1425        }
1426            
1427        // generate:
1428
// return fieldX;
1429
// and add to the end of exprFun's body.
1430
exprFun.getField(lf);
1431        exprFun.methodReturn();
1432
1433        // we are done putting stuff in exprFun:
1434
exprFun.complete();
1435
1436        return exprFun;
1437    }
1438
1439    /**
1440     * Generate the code to create an empty row in the constructor.
1441     *
1442     * @param acb The ACB.
1443     * @param field The field for the new row.
1444     * @param rowAllocatorMethod The method to call.
1445     * @param rowAllocatorType The row type.
1446     * @param numCols The number of columns in the row.
1447     *
1448     * @exception StandardException Thrown on error
1449     */

1450    private void genCreateRow(ExpressionClassBuilder acb,
1451                              LocalField field,
1452                              String JavaDoc rowAllocatorMethod,
1453                              String JavaDoc rowAllocatorType,
1454                              int numCols)
1455        throws StandardException
1456    {
1457        // Create the row in the constructor
1458
// fieldX = getExecutionFactory().getValueRow(# cols);
1459

1460        MethodBuilder cb = acb.getConstructor();
1461
1462        acb.pushGetExecutionFactoryExpression(cb); // instance
1463
cb.push(numCols);
1464        cb.callMethod(VMOpcode.INVOKEINTERFACE, (String JavaDoc) null,
1465                            rowAllocatorMethod, rowAllocatorType, 1);
1466        cb.setField(field);
1467        /* Increase the statement counter in constructor. Code size in
1468         * constructor can become too big (more than 64K) for Java compiler
1469         * to handle (beetle 4293). We set constant columns in other
1470         * methods if constructor has too many statements already.
1471         */

1472        cb.statementNumHitLimit(1); // ignore return value
1473
}
1474
1475    /**
1476     * Make a ResultDescription for use in a ResultSet.
1477     * This is useful when generating/executing a NormalizeResultSet, since
1478     * it can appear anywhere in the tree.
1479     *
1480     * @return A ResultDescription for this ResultSetNode.
1481     */

1482
1483    public ResultColumnDescriptor[] makeResultDescriptors()
1484    {
1485        ExecutionContext ec = (ExecutionContext) getContextManager().getContext(
1486            ExecutionContext.CONTEXT_ID);
1487        return makeResultDescriptors(ec);
1488    }
1489
1490    ResultColumnDescriptor[] makeResultDescriptors(ExecutionContext ec)
1491    {
1492        ResultColumnDescriptor colDescs[] = new ResultColumnDescriptor[size()];
1493        int size = size();
1494
1495        for (int index = 0; index < size; index++)
1496        {
1497            // the ResultColumn nodes are descriptors, so take 'em...
1498
colDescs[index] = ec.getExecutionFactory().getResultColumnDescriptor(((ResultColumnDescriptor) elementAt(index)));
1499        }
1500
1501        return colDescs;
1502    }
1503
1504    /**
1505     * Expand any *'s in the ResultColumnList. In addition, we will guarantee that
1506     * each ResultColumn has a name. (All generated names will be unique across the
1507     * entire statement.)
1508     *
1509     *
1510     * @exception StandardException Thrown on error
1511     */

1512
1513    public void expandAllsAndNameColumns(FromList fromList)
1514                    throws StandardException
1515    {
1516        boolean expanded = false;
1517        ResultColumnList allExpansion;
1518        TableName fullTableName;
1519
1520        /* First walk result column list looking for *'s to expand */
1521        for (int index = 0; index < size(); index++)
1522        {
1523            ResultColumn rc = (ResultColumn) elementAt(index);
1524            if (rc instanceof AllResultColumn)
1525            {
1526                expanded = true;
1527
1528                //fullTableName = ((AllResultColumn) rc).getFullTableName();
1529
TableName temp = rc.getTableNameObject();
1530                if(temp != null) {
1531                   String JavaDoc sName = temp.getSchemaName();
1532                   String JavaDoc tName = temp.getTableName();
1533                   fullTableName = makeTableName(sName,tName);
1534                }
1535                else
1536                   fullTableName = null;
1537                allExpansion = fromList.expandAll(fullTableName);
1538
1539                /* Make sure that every column has a name */
1540                allExpansion.nameAllResultColumns();
1541
1542                /* Make sure that every RC and expression is marked as being in
1543                 * the SELECT list.
1544                 */

1545                allExpansion.setClause(ValueNode.IN_SELECT_LIST);
1546
1547                /* Replace the AllResultColumn with the expanded list.
1548                 * We will update the VirtualColumnIds once below.
1549                 */

1550                removeElementAt(index);
1551                for (int inner = 0; inner < allExpansion.size(); inner++)
1552                {
1553                    insertElementAt(allExpansion.elementAt(inner), index + inner);
1554                }
1555
1556                // If the rc was a "*", we need to set the initial list size
1557
// to the number of columns that are actually returned to
1558
// the user.
1559
markInitialSize();
1560            }
1561            else
1562            {
1563                /* Make sure that every column has a name */
1564                rc.guaranteeColumnName();
1565            }
1566        }
1567
1568        /* Go back and update the VirtualColumnIds if we expanded any *'s */
1569        if (expanded)
1570        {
1571            int size = size();
1572
1573            for (int index = 0; index < size; index++)
1574            {
1575                /* Vectors are 0-based, VirtualColumnIds are 1-based. */
1576                ((ResultColumn) elementAt(index)).setVirtualColumnId(index + 1);
1577            }
1578        }
1579    }
1580
1581    /**
1582     * Generate (unique across the entire statement) column names for those
1583     * ResultColumns in this list which are not named.
1584     *
1585     * @exception StandardException Thrown on error
1586     */

1587    public void nameAllResultColumns()
1588        throws StandardException
1589    {
1590        int size = size();
1591
1592        for (int index = 0; index < size; index++)
1593        {
1594            ResultColumn resultColumn = (ResultColumn) elementAt(index);
1595
1596            resultColumn.guaranteeColumnName();
1597        }
1598    }
1599
1600    /**
1601     * Copy the types and lengths for this RCL (the target)
1602     * to another RCL (the source).
1603     * This is useful when adding a NormalizeResultSetNode.
1604     *
1605     * @param sourceRCL The source RCL
1606     */

1607    public void copyTypesAndLengthsToSource(ResultColumnList sourceRCL) throws StandardException
1608    {
1609        /* Source and target can have different lengths. */
1610        int size = (size() > sourceRCL.size()) ? size() : sourceRCL.size();
1611        for (int index = 0; index < size; index++)
1612        {
1613            ResultColumn sourceRC = (ResultColumn) sourceRCL.elementAt(index);
1614            ResultColumn resultColumn = (ResultColumn) elementAt(index);
1615            sourceRC.setType(resultColumn.getTypeServices());
1616            sourceRC.getExpression().setType(resultColumn.getTypeServices());
1617        }
1618    }
1619        
1620
1621    /*
1622    ** Check whether the column lengths and types of the result columns
1623    ** match the expressions under those columns. This is useful for
1624    ** INSERT and UPDATE statements. For SELECT statements this method
1625    ** should always return true. There is no need to call this for a
1626    ** DELETE statement.
1627    ** NOTE: We skip over generated columns since they won't have a
1628    ** column descriptor.
1629    **
1630    ** @return true means all the columns match their expressions,
1631    ** false means at least one column does not match its
1632    ** expression
1633    */

1634
1635    boolean columnTypesAndLengthsMatch()
1636        throws StandardException
1637    {
1638        int size = size();
1639
1640        for (int index = 0; index < size; index++)
1641        {
1642            ResultColumn resultColumn = (ResultColumn) elementAt(index);
1643
1644            /* Skip over generated columns */
1645            if (resultColumn.isGenerated())
1646            {
1647                continue;
1648            }
1649
1650            if (! resultColumn.columnTypeAndLengthMatch())
1651                return false;
1652        }
1653
1654        return true;
1655    }
1656
1657    boolean columnTypesAndLengthsMatch(ResultColumnList otherRCL)
1658        throws StandardException
1659    {
1660        boolean retval = true;
1661
1662        /* We check every RC, even after finding 1 that requires
1663         * normalization, because the conversion of constants to
1664         * the appropriate type occurs under this loop.
1665         */

1666        int size = size();
1667        for (int index = 0; index < size; index++)
1668        {
1669            ResultColumn resultColumn = (ResultColumn) elementAt(index);
1670
1671            ResultColumn otherResultColumn = (ResultColumn) otherRCL.elementAt(index);
1672
1673            /* Skip over generated columns */
1674            if (resultColumn.isGenerated() || otherResultColumn.isGenerated())
1675            {
1676                continue;
1677            }
1678
1679            if (! resultColumn.columnTypeAndLengthMatch(otherResultColumn))
1680            {
1681                retval = false;
1682            }
1683        }
1684
1685        return retval;
1686    }
1687
1688    /**
1689     * Determine whether this RCL is a No-Op projection of the given RCL.
1690     * It only makes sense to do this if the given RCL is from the child
1691     * result set of the ProjectRestrict that this RCL is from.
1692     *
1693     * @param childRCL The ResultColumnList of the child result set.
1694     *
1695     * @return true if this RCL is a No-Op projection of the given RCL.
1696     */

1697    public boolean nopProjection(ResultColumnList childRCL)
1698    {
1699        /*
1700        ** This RCL is a useless projection if each column in the child
1701        ** if the same as the column in this RCL. This is impossible
1702        ** if the two RCLs have different numbers of columns.
1703        */

1704        if (this.size() != childRCL.size())
1705        {
1706            return false;
1707        }
1708
1709        /*
1710        ** The two lists have the same numbers of elements. Are the lists
1711        ** identical? In other words, is the expression in every ResultColumn
1712        ** in the PRN's RCL a ColumnReference that points to the corresponding
1713        ** column in the child?
1714        */

1715        int size = size();
1716        for (int index = 0; index < size; index++)
1717        {
1718            ResultColumn thisColumn = (ResultColumn) elementAt(index);
1719            ResultColumn referencedColumn = null;
1720
1721            /*
1722            ** A No-Op projection can point to a VirtualColumnNode or a
1723            ** ColumnReference.
1724            */

1725            if (thisColumn.getExpression() instanceof VirtualColumnNode)
1726            {
1727                referencedColumn =
1728                    ((VirtualColumnNode) (thisColumn.getExpression())).
1729                                                            getSourceColumn();
1730            }
1731            else if (thisColumn.getExpression() instanceof ColumnReference)
1732            {
1733                referencedColumn =
1734                    ((ColumnReference) (thisColumn.getExpression())).
1735                                                                getSource();
1736            }
1737            else
1738            {
1739                return false;
1740            }
1741
1742            ResultColumn childColumn = (ResultColumn) childRCL.elementAt(index);
1743
1744            if (referencedColumn != childColumn)
1745            {
1746                return false;
1747            }
1748        }
1749
1750        return true;
1751    }
1752
1753    /**
1754     * Create a shallow copy of a ResultColumnList and its ResultColumns.
1755     * (All other pointers are preserved.)
1756     * Useful for building new ResultSetNodes during preprocessing.
1757     *
1758     * @return None.
1759     *
1760     * @exception StandardException Thrown on error
1761     */

1762    public ResultColumnList copyListAndObjects()
1763                    throws StandardException
1764    {
1765        ResultColumn newResultColumn;
1766        ResultColumn origResultColumn;
1767        ResultColumnList newList;
1768
1769        /* Create the new ResultColumnList */
1770        newList = (ResultColumnList) getNodeFactory().getNode(
1771                                        C_NodeTypes.RESULT_COLUMN_LIST,
1772                                        getContextManager());
1773
1774        /* Walk the current list - for each ResultColumn in the list, make a copy
1775         * and add it to the new list.
1776         */

1777        int size = size();
1778
1779        for (int index = 0; index < size; index++)
1780        {
1781            origResultColumn = (ResultColumn) elementAt(index);
1782
1783            newResultColumn = origResultColumn.cloneMe();
1784
1785            newList.addResultColumn(newResultColumn);
1786        }
1787
1788        return newList;
1789    }
1790
1791    /**
1792     * Walk the list and replace ResultColumn.expression with a new
1793     * VirtualColumnNode. This is useful when propagating a ResultColumnList
1794     * up the query tree.
1795     * NOTE: This flavor marks all of the underlying RCs as referenced.
1796     *
1797     * @param sourceResultSet ResultSetNode that is source of value
1798     *
1799     * @exception StandardException Thrown on error
1800     */

1801    public void genVirtualColumnNodes(ResultSetNode sourceResultSet,
1802                                      ResultColumnList sourceResultColumnList)
1803                throws StandardException
1804    {
1805        genVirtualColumnNodes(sourceResultSet, sourceResultColumnList, true);
1806    }
1807
1808
1809
1810    /**
1811     * Walk the list and replace ResultColumn.expression with a new
1812     * VirtualColumnNode. This is useful when propagating a ResultColumnList
1813     * up the query tree.
1814     *
1815     * @param sourceResultSet ResultSetNode that is source of value
1816     * @param markReferenced Whether or not to mark the underlying RCs
1817     * as referenced
1818     *
1819     * @exception StandardException Thrown on error
1820     */

1821    public void genVirtualColumnNodes(ResultSetNode sourceResultSet,
1822                                      ResultColumnList sourceResultColumnList,
1823                                      boolean markReferenced)
1824                throws StandardException
1825    {
1826        int size = size();
1827
1828        for (int index = 0; index < size; index++)
1829        {
1830            ResultColumn resultColumn = (ResultColumn) elementAt(index);
1831
1832            /* dts = resultColumn.getExpression().getTypeServices(); */
1833            DataTypeDescriptor dts = resultColumn.getTypeServices();
1834
1835            /* Vectors are 0-based, VirtualColumnIds are 1-based */
1836            resultColumn.expression = (ValueNode) getNodeFactory().getNode(
1837                            C_NodeTypes.VIRTUAL_COLUMN_NODE,
1838                            sourceResultSet,
1839                            sourceResultColumnList.elementAt(index),
1840                            ReuseFactory.getInteger(index + 1),
1841                            getContextManager());
1842
1843            /* Mark the ResultColumn as being referenced */
1844            if (markReferenced)
1845            {
1846                resultColumn.setReferenced();
1847            }
1848        }
1849    }
1850
1851    /**
1852     * Walk the list and adjust the virtualColumnIds in the ResultColumns
1853     * by the specified amount. If ResultColumn.expression is a VirtualColumnNode,
1854     * then we adjust the columnId there as well.
1855     *
1856     * @param adjust The size of the increment.
1857     */

1858    public void adjustVirtualColumnIds(int adjust)
1859    {
1860        int size = size();
1861
1862        for (int index = 0; index < size; index++)
1863        {
1864            ResultColumn resultColumn = (ResultColumn) elementAt(index);
1865            resultColumn.adjustVirtualColumnId(adjust);
1866            if (SanityManager.DEBUG)
1867            {
1868                if ( !
1869                    (resultColumn.getExpression() instanceof VirtualColumnNode))
1870                {
1871                    SanityManager.THROWASSERT(
1872                        "resultColumn.getExpression() is expected to be " +
1873                        "instanceof VirtualColumnNode" +
1874                        " not " +
1875                        resultColumn.getExpression().getClass().getName());
1876                }
1877            }
1878
1879            ((VirtualColumnNode) resultColumn.getExpression()).columnId += adjust;
1880        }
1881    }
1882
1883    /**
1884     * Project out any unreferenced ResultColumns from the list and
1885     * reset the virtual column ids in the referenced ResultColumns.
1886     * If all ResultColumns are projected out, then the list is not empty.
1887     *
1888     * @exception StandardException Thrown on error
1889     */

1890    public void doProjection() throws StandardException
1891    {
1892        int numDeleted = 0;
1893        int size = size();
1894        ResultColumnList deletedRCL = new ResultColumnList();
1895        for (int index = 0; index < size; index++)
1896        {
1897            ResultColumn resultColumn = (ResultColumn) elementAt(index);
1898
1899            /* RC's for FromBaseTables are marked as referenced during binding.
1900             * For other nodes, namely JoinNodes, we need to go 1 level
1901             * down the RC/VCN chain to see if the RC is referenced. This is
1902             * because we propagate the referencing info from the bottom up.
1903             */

1904            if ((! resultColumn.isReferenced()) &&
1905                (resultColumn.getExpression() instanceof VirtualColumnNode) &&
1906                !(((VirtualColumnNode) resultColumn.getExpression()).getSourceColumn().isReferenced()))
1907            {
1908                // Remember the RC to delete when done
1909
deletedRCL.addElement(resultColumn);
1910
1911                /* Remember how many we have deleted and decrement the
1912                 * VirtualColumnIds for all nodes which appear after us
1913                 * in the list.
1914                 */

1915                numDeleted++;
1916            }
1917            else
1918            {
1919                /* Decrement the VirtualColumnId for each node in the list
1920                 * after the 1st deleted one.
1921                 */

1922                if (numDeleted >= 1)
1923                    resultColumn.adjustVirtualColumnId( - numDeleted);
1924                /* Make sure that the RC is marked as referenced! */
1925                resultColumn.setReferenced();
1926            }
1927        }
1928
1929        // Go back and delete the RCs to be delete from the list
1930
for (int index = 0; index < deletedRCL.size(); index++)
1931        {
1932            removeElement((ResultColumn) deletedRCL.elementAt(index));
1933        }
1934    }
1935
1936    /**
1937     * Check the uniqueness of the column names within a column list.
1938     *
1939     * @param errForGenCols Raise an error for any generated column names.
1940     *
1941     * @return String The first duplicate column name, if any.
1942     */

1943    public String JavaDoc verifyUniqueNames(boolean errForGenCols)
1944                    throws StandardException
1945    {
1946        int size = size();
1947        Hashtable JavaDoc ht = new Hashtable JavaDoc(size + 2, (float) .999);
1948        ResultColumn rc;
1949
1950        for (int index = 0; index < size; index++)
1951        {
1952            rc = (ResultColumn) elementAt(index);
1953            if (errForGenCols && rc.isNameGenerated())
1954                throw StandardException.newException(SQLState.LANG_DB2_VIEW_REQUIRES_COLUMN_NAMES);
1955            /* Verify that this column's name is unique within the list */
1956            String JavaDoc colName = ((ResultColumn) elementAt(index)).getName();
1957
1958            Object JavaDoc object = ht.put(colName, colName);
1959
1960            if (object != null &&
1961                ((String JavaDoc) object).equals(colName))
1962            {
1963                return colName;
1964            }
1965        }
1966
1967        /* No duplicate column names */
1968        return null;
1969    }
1970
1971    /**
1972     * Validate the derived column list (DCL) and propagate the info
1973     * from the list to the final ResultColumnList.
1974     *
1975     * @param derivedRCL The derived column list
1976     * @param tableName The table name for the FromTable
1977     *
1978     * @exception StandardException Thrown on error
1979     */

1980    public void propagateDCLInfo(ResultColumnList derivedRCL, String JavaDoc tableName)
1981                    throws StandardException
1982    {
1983        String JavaDoc duplicateColName;
1984
1985        /* Do both lists, if supplied by user, have the same degree? */
1986        if (derivedRCL.size() != size() &&
1987            ! derivedRCL.getCountMismatchAllowed())
1988        {
1989            throw StandardException.newException(SQLState.LANG_DERIVED_COLUMN_LIST_MISMATCH, tableName);
1990        }
1991
1992        /* Check the uniqueness of the column names within the derived list */
1993        duplicateColName = derivedRCL.verifyUniqueNames(false);
1994        if (duplicateColName != null)
1995        {
1996            throw StandardException.newException(SQLState.LANG_DUPLICATE_COLUMN_NAME_DERIVED, duplicateColName);
1997        }
1998
1999        /* We can finally copy the derived names into the final list */
2000        copyResultColumnNames(derivedRCL);
2001    }
2002
2003    /**
2004     * Look for and reject ? parameters under ResultColumns. This is done for
2005     * SELECT statements.
2006     *
2007     * @exception StandardException Thrown if a ? parameter found directly
2008     * under a ResultColumn
2009     */

2010
2011    void rejectParameters() throws StandardException
2012    {
2013        int size = size();
2014
2015        for (int index = 0; index < size; index++)
2016        {
2017            ResultColumn rc = (ResultColumn) elementAt(index);
2018            rc.rejectParameter();
2019        }
2020    }
2021
2022    /**
2023     * Check for (and reject) XML values directly under the ResultColumns.
2024     * This is done for SELECT/VALUES statements. We reject values
2025     * in this case because JDBC does not define an XML type/binding
2026     * and thus there's no standard way to pass such a type back
2027     * to a JDBC application.
2028     *
2029     * Note that we DO allow an XML column in a top-level RCL
2030     * IF that column was added to the RCL by _us_ instead of
2031     * by the user. For example, if we have a table:
2032     *
2033     * create table t1 (i int, x xml)
2034     *
2035     * and the user query is:
2036     *
2037     * select i from t1 order by x
2038     *
2039     * the "x" column will be added (internally) to the RCL
2040     * as part of ORDER BY processing--and so we need to
2041     * allow that XML column to be bound without throwing
2042     * an error. If, as in this case, the XML column reference
2043     * is invalid (we can't use ORDER BY on an XML column because
2044     * XML values aren't ordered), a more appropriate error
2045     * message should be returned to the user in later processing.
2046     * If we didn't allow for this, the user would get an
2047     * error saying that XML columns are not valid as part
2048     * of the result set--but as far as s/he knows, there
2049     * isn't such a column: only "i" is supposed to be returned
2050     * (the RC for "x" was added to the RCL by _us_ as part of
2051     * ORDER BY processing).
2052     *
2053     * ASSUMPTION: Any RCs that are generated internally and
2054     * added to this RCL (before this RCL is bound) are added
2055     * at the _end_ of the list. If that's true, then any
2056     * RC with an index greater than the size of the initial
2057     * (user-specified) list must have been added internally
2058     * and will not be returned to the user.
2059     *
2060     * @exception StandardException Thrown if an XML value found
2061     * directly under a ResultColumn
2062     */

2063    void rejectXMLValues() throws StandardException
2064    {
2065        int sz = size();
2066        ResultColumn rc = null;
2067        for (int i = 1; i <= sz; i++) {
2068
2069            if (i > initialListSize)
2070            // this RC was generated internally and will not
2071
// be returned to the user, so don't throw error.
2072
continue;
2073
2074            rc = getResultColumn(i);
2075            if ((rc != null) && (rc.getType() != null) &&
2076                rc.getType().getTypeId().isXMLTypeId())
2077            { // Disallow it.
2078
throw StandardException.newException(
2079                    SQLState.LANG_ATTEMPT_TO_SELECT_XML);
2080            }
2081
2082        }
2083    }
2084
2085    /**
2086     * Set the resultSetNumber in all of the ResultColumns.
2087     *
2088     * @param resultSetNumber The resultSetNumber
2089     */

2090    public void setResultSetNumber(int resultSetNumber)
2091    {
2092        int size = size();
2093
2094        for (int index = 0; index < size; index++)
2095        {
2096            ((ResultColumn) elementAt(index)).setResultSetNumber(resultSetNumber);
2097        }
2098    }
2099
2100    /**
2101     * Mark all of the ResultColumns as redundant.
2102     * Useful when chopping a ResultSetNode out of a tree when there are
2103     * still references to its RCL.
2104     */

2105    public void setRedundant()
2106    {
2107        int size = size();
2108
2109        for (int index = 0; index < size; index++)
2110        {
2111            ((ResultColumn) elementAt(index)).setRedundant();
2112        }
2113    }
2114
2115    /**
2116     * Verify that all of the columns in the SET clause of a positioned update
2117     * appear in the cursor's FOR UPDATE OF list.
2118     *
2119     * @param ucl The cursor's FOR UPDATE OF list. (May be null.)
2120     * @param cursorName The cursor's name.
2121     *
2122     * @exception StandardException Thrown on error
2123     */

2124    public void checkColumnUpdateability(String JavaDoc[] ucl, String JavaDoc cursorName)
2125            throws StandardException
2126    {
2127        int size = size();
2128
2129        for (int index = 0; index < size; index++)
2130        {
2131            ResultColumn resultColumn = (ResultColumn) elementAt(index);
2132
2133            if (resultColumn.updated() &&
2134                ! resultColumn.foundInList(ucl))
2135            {
2136                throw StandardException.newException(SQLState.LANG_COLUMN_NOT_UPDATABLE_IN_CURSOR,
2137                            resultColumn.getName(),
2138                            cursorName);
2139            }
2140        }
2141    }
2142
2143    /**
2144     * Set up the result expressions for a UNION, INTERSECT, or EXCEPT:
2145     * o Verify union type compatiblity
2146     * o Get dominant type for result (type + max length + nullability)
2147     * o Create a new ColumnReference with dominant type and name of from this
2148     * RCL and make that the new expression.
2149     * o Set the type info for in the ResultColumn to the dominant type
2150     *
2151     * NOTE - We are assuming that caller has generated a new RCL for the UNION
2152     * with the same names as the left side's RCL and copies of the expressions.
2153     *
2154     * @param otherRCL RCL from other side of the UNION.
2155     * @param tableNumber The tableNumber for the UNION.
2156     * @param level The nesting level for the UNION.
2157     * @param operatorName "UNION", "INTERSECT", or "EXCEPT"
2158     *
2159     * @exception StandardException Thrown on error
2160     */

2161    public void setUnionResultExpression(ResultColumnList otherRCL,
2162                                         int tableNumber,
2163                                         int level,
2164                                         String JavaDoc operatorName)
2165        throws StandardException
2166    {
2167        TableName dummyTN;
2168
2169        if (SanityManager.DEBUG)
2170        {
2171            if (size() != otherRCL.size())
2172            {
2173                SanityManager.THROWASSERT(
2174                            "size() = (" +
2175                            size() +
2176                            ") is expected to equal otherRCL.size (" +
2177                            otherRCL.size() +
2178                            ")");
2179            }
2180        }
2181
2182        /* Make a dummy TableName to be shared by all new CRs */
2183        dummyTN = (TableName) getNodeFactory().getNode(
2184                                        C_NodeTypes.TABLE_NAME,
2185                                        null,
2186                                        null,
2187                                        getContextManager());
2188
2189        ContextManager cm = getContextManager();
2190
2191        int size = size();
2192        for (int index = 0; index < size; index++)
2193        {
2194            boolean nullableResult;
2195            ColumnReference newCR;
2196            ResultColumn thisRC = (ResultColumn) elementAt(index);
2197            ResultColumn otherRC = (ResultColumn) otherRCL.elementAt(index);
2198            ValueNode thisExpr = thisRC.getExpression();
2199            ValueNode otherExpr = otherRC.getExpression();
2200
2201            // If there is one row that is not 'autoincrement', the Union should
2202
// not be 'autoincrement'.
2203
if (!otherRC.isAutoincrementGenerated() && thisRC.isAutoincrementGenerated())
2204            {
2205                thisRC.resetAutoincrementGenerated();
2206            }
2207            /*
2208            ** If there are ? parameters in the ResultColumnList of a row
2209            ** in a table constructor, their types will not be set. Just skip
2210            ** these - their types will be set later. Each ? parameter will
2211            ** get the type of the first non-? in its column, so it can't
2212            ** affect the final dominant type. It's possible that all the
2213            ** rows for a particular column will have ? parameters - this is
2214            ** an error condition that will be caught later.
2215            */

2216            TypeId thisTypeId = thisExpr.getTypeId();
2217            if (thisTypeId == null)
2218                continue;
2219
2220            TypeId otherTypeId = otherExpr.getTypeId();
2221            if (otherTypeId == null)
2222                continue;
2223
2224            /*
2225            ** Check type compatability. We want to make sure that
2226            ** the types are assignable in either direction
2227            ** and they are comparable.
2228            */

2229            ClassFactory cf = getClassFactory();
2230            if (
2231                !thisExpr.getTypeCompiler().storable(otherTypeId, cf) &&
2232                !otherExpr.getTypeCompiler().storable(thisTypeId, cf))
2233            {
2234                throw StandardException.newException(SQLState.LANG_NOT_UNION_COMPATIBLE,
2235                                                     thisTypeId.getSQLTypeName(),
2236                                                     otherTypeId.getSQLTypeName(),
2237                                                     operatorName);
2238            }
2239
2240            DataTypeDescriptor resultType = thisExpr.getTypeServices().getDominantType(
2241                                                otherExpr.getTypeServices(),
2242                                                cf);
2243
2244            newCR = (ColumnReference) getNodeFactory().getNode(
2245                                        C_NodeTypes.COLUMN_REFERENCE,
2246                                        thisRC.getName(),
2247                                        dummyTN,
2248                                        getContextManager());
2249            newCR.setType(resultType);
2250            /* Set the tableNumber and nesting levels in newCR.
2251             * If thisExpr is not a CR, then newCR cannot be
2252             * correlated, hence source and nesting levels are
2253             * the same.
2254             */

2255            if (thisExpr instanceof ColumnReference)
2256            {
2257                newCR.copyFields((ColumnReference) thisExpr);
2258            }
2259            else
2260            {
2261                newCR.setNestingLevel(level);
2262                newCR.setSourceLevel(level);
2263            }
2264            newCR.setTableNumber(tableNumber);
2265            thisRC.setExpression(newCR);
2266            thisRC.setType(
2267                thisRC.getTypeServices().getDominantType(
2268                    otherRC.getTypeServices(), cf));
2269
2270            /* DB2 requires both sides of union to have same name for the result to
2271             * have that name. Otherwise, leave it or set it to a generated name */

2272            if (thisRC.getName() != null && !thisRC.isNameGenerated() &&
2273                otherRC.getName() != null)
2274            {
2275                /* Result name needs to be changed */
2276                if (otherRC.isNameGenerated())
2277                {
2278                    thisRC.setName(otherRC.getName());
2279                    thisRC.setNameGenerated(true);
2280                }
2281                else if (!thisRC.getName().equals(otherRC.getName()))
2282                {
2283                    /* Both sides have user specified names that don't match */
2284                    thisRC.setName(null);
2285                    thisRC.guaranteeColumnName();
2286                    thisRC.setNameGenerated(true);
2287                }
2288            }
2289        }
2290    }
2291
2292    /**
2293     * If the resultset is a UnionNode (e.g., multi-rows in VALUES clause), we recursively call itself.
2294     * checkAutoincrement() will set ColumnDescriptor for autoincrement columns.
2295     * This way, all ColumnDescriptor of all rows will be set properly.
2296     */

2297    public void checkAutoincrementUnion(ResultSetNode rs)
2298        throws StandardException
2299    {
2300        ResultSetNode lrs = ((TableOperatorNode)rs).getLeftResultSet();
2301        ResultSetNode rrs = ((TableOperatorNode)rs).getRightResultSet();
2302
2303        if (lrs instanceof UnionNode)
2304        {
2305            this.checkAutoincrementUnion(lrs);
2306        }
2307        else
2308        {
2309            this.checkAutoincrement(lrs.getResultColumns());
2310        }
2311
2312        if (rrs instanceof UnionNode)
2313        {
2314            this.checkAutoincrementUnion(rrs);
2315        }
2316        else
2317        {
2318            this.checkAutoincrement(rrs.getResultColumns());
2319        }
2320    }
2321
2322    /**
2323     * Do the 2 RCLs have the same type & length.
2324     * This is useful for UNIONs when deciding whether a NormalizeResultSet is required.
2325     *
2326     * @param otherRCL The other RCL.
2327     *
2328     * @return boolean Whether or not there is an exact UNION type match on the 2 RCLs.
2329     */

2330    public boolean isExactTypeAndLengthMatch(ResultColumnList otherRCL) throws StandardException
2331    {
2332        int size = size();
2333        for (int index = 0; index < size; index++)
2334        {
2335            ResultColumn thisRC = (ResultColumn) elementAt(index);
2336            ResultColumn otherRC = (ResultColumn) otherRCL.elementAt(index);
2337
2338            if (! thisRC.getTypeServices().isExactTypeAndLengthMatch(
2339                                                otherRC.getTypeServices() ))
2340            {
2341                return false;
2342            }
2343        }
2344
2345        return true;
2346    }
2347
2348    /**
2349     * Does the column list contain any of the given column positions
2350     * that are updated? Implements same named routine in UpdateList.
2351     *
2352     * @param columns An array of column positions
2353     *
2354     * @return True if this column list contains any of the given columns
2355     */

2356    public boolean updateOverlaps(int[] columns)
2357    {
2358        int size = size();
2359
2360        for (int index = 0; index < size; index++)
2361        {
2362            ResultColumn rc = (ResultColumn) elementAt(index);
2363
2364            if ( ! rc.updated())
2365                continue;
2366
2367            int column = rc.getColumnPosition();
2368
2369            for (int i = 0; i < columns.length; i++)
2370            {
2371                if (columns[i] == column)
2372                    return true;
2373            }
2374        }
2375
2376        return false;
2377    }
2378
2379    /**
2380     * Return an array that contains references to the columns in this list
2381     * sorted by position.
2382     *
2383     * @return The sorted array.
2384     */

2385    ResultColumn[] getSortedByPosition()
2386    {
2387        int size = size();
2388        ResultColumn[] result;
2389        
2390        /*
2391        ** Form an array of the original ResultColumns
2392        */

2393        result = new ResultColumn[size];
2394
2395        /*
2396        ** Put the ResultColumns in the array
2397        */

2398        for (int index = 0; index < size; index++)
2399        {
2400            result[index] = (ResultColumn) elementAt(index);
2401        }
2402
2403        /*
2404        ** Sort the array by column position
2405        */

2406        java.util.Arrays.sort(result);
2407        return result;
2408    }
2409
2410    /**
2411      * Return an array of all my column positions, sorted in
2412      * ascending order.
2413      *
2414      * @return a sorted array
2415      */

2416    public int[] sortMe()
2417    {
2418        ResultColumn[] sortedResultColumns = getSortedByPosition();
2419        int[] sortedColumnIds = new int[sortedResultColumns.length];
2420        for (int ix = 0; ix < sortedResultColumns.length; ix++)
2421        {
2422            sortedColumnIds[ix] = sortedResultColumns[ix].getColumnPosition();
2423        }
2424        return sortedColumnIds;
2425    }
2426
2427
2428    /**
2429     * Expand this ResultColumnList by adding all columns from the given
2430     * table that are not in this list. The result is sorted by column
2431     * position.
2432     *
2433     * @param td The TableDescriptor for the table in question
2434     * @param tableName The name of the table as given in the query
2435     *
2436     * @return A new ResultColumnList expanded to include all columns in
2437     * the given table.
2438     *
2439     * @exception StandardException Thrown on error
2440     */

2441    public ResultColumnList expandToAll(TableDescriptor td,
2442                                TableName tableName)
2443                        throws StandardException
2444    {
2445        ResultColumn rc;
2446        ColumnDescriptor cd;
2447        ResultColumnList retval;
2448        ResultColumn[] originalRCS;
2449        int posn;
2450
2451        /* Get a new ResultColumnList */
2452        retval = (ResultColumnList) getNodeFactory().getNode(
2453                                        C_NodeTypes.RESULT_COLUMN_LIST,
2454                                        getContextManager());
2455
2456        /*
2457        ** Form a sorted array of the ResultColumns
2458        */

2459        originalRCS = getSortedByPosition();
2460
2461        posn = 0;
2462 
2463        /* Iterate through the ColumnDescriptors for the given table */
2464        ColumnDescriptorList cdl = td.getColumnDescriptorList();
2465        int cdlSize = cdl.size();
2466
2467        for (int index = 0; index < cdlSize; index++)
2468        {
2469            cd = (ColumnDescriptor) cdl.elementAt(index);
2470
2471            if ((posn < originalRCS.length) &&
2472                (cd.getPosition() == originalRCS[posn].getColumnPosition()))
2473            {
2474                rc = originalRCS[posn];
2475                posn++;
2476            }
2477            else
2478            {
2479                /* Build a ResultColumn/ColumnReference pair for the column */
2480                rc = makeColumnReferenceFromName( tableName, cd.getColumnName() );
2481
2482                /* Bind the new ResultColumn */
2483                rc.bindResultColumnByPosition(td, cd.getPosition());
2484            }
2485
2486            /* Add the ResultColumn to the list */
2487            retval.addResultColumn(rc);
2488        }
2489
2490        if (SanityManager.DEBUG)
2491        SanityManager.ASSERT(posn == originalRCS.length,
2492        "ResultColumns in original list not added to expanded ResultColumnList");
2493
2494        return retval;
2495    }
2496
2497    /**
2498     * Bind any untyped null nodes to the types in the given ResultColumnList.
2499     * Nodes that don't know their type may pass down nulls to
2500     * children nodes. In the case of something like a union, it knows
2501     * to try its right and left result sets against each other.
2502     * But if a null reaches us, it means we have a null type that
2503     * we don't know how to handle.
2504     *
2505     * @param bindingRCL The ResultColumnList with the types to bind to.
2506     *
2507     * @exception StandardException Thrown on error
2508     */

2509    public void bindUntypedNullsToResultColumns(ResultColumnList bindingRCL)
2510                throws StandardException
2511    {
2512        if (bindingRCL == null)
2513        {
2514            throw StandardException.newException(SQLState.LANG_NULL_IN_VALUES_CLAUSE);
2515        }
2516        
2517        if (SanityManager.DEBUG)
2518            SanityManager.ASSERT(bindingRCL.size() >= this.size(),
2519                    "More columns in result column list than in base table");
2520
2521        int size = size();
2522        for (int index = 0; index < size; index++)
2523        {
2524            ResultColumn bindingRC = (ResultColumn) bindingRCL.elementAt(index);
2525            ResultColumn thisRC = (ResultColumn) elementAt(index);
2526
2527            thisRC.typeUntypedNullExpression(bindingRC);
2528        }
2529    }
2530
2531    /**
2532     * Mark all the columns in this list as updated by an update statement.
2533     */

2534    void markUpdated()
2535    {
2536        int size = size();
2537
2538        for (int index = 0; index < size; index++)
2539        {
2540            ((ResultColumn) elementAt(index)).markUpdated();
2541        }
2542    }
2543
2544    /**
2545     * Mark all the (base) columns in this list as updatable by a positioned update
2546     * statement. This is necessary
2547     * for positioned update statements, because we expand the column list
2548     * to include all the columns in the base table, and we need to be able
2549     * to tell which ones the user is really trying to update so we can
2550     * determine correctly whether all the updated columns are in the
2551     * "for update" list.
2552     */

2553    void markUpdatableByCursor()
2554    {
2555        int size = size();
2556
2557        for (int index = 0; index < size; index++)
2558        {
2559            //determine if the column is a base column and not a derived column
2560
if (((ResultColumn) elementAt(index)).getSourceTableName() != null)
2561                ((ResultColumn) elementAt(index)).markUpdatableByCursor();
2562        }
2563    }
2564
2565    /**
2566     * @see QueryTreeNode#disablePrivilegeCollection
2567     */

2568    public void disablePrivilegeCollection()
2569    {
2570        super.disablePrivilegeCollection();
2571
2572        int size = size();
2573        for (int index = 0; index < size; index++)
2574            ((ResultColumn) elementAt(index)).disablePrivilegeCollection();
2575    }
2576    
2577    /**
2578     * Verify that all of the column names in this list are contained
2579     * within the ColumnDefinitionNodes within the TableElementList.
2580     *
2581     *
2582     * @return String The 1st column name, if any, that is not in the list.
2583     */

2584    public String JavaDoc verifyCreateConstraintColumnList(TableElementList tel)
2585    {
2586        int size = size();
2587
2588        for (int index = 0; index < size; index++)
2589        {
2590            String JavaDoc colName = ((ResultColumn) elementAt(index)).getName();
2591
2592            if (! tel.containsColumnName(colName))
2593            {
2594                return colName;
2595            }
2596        }
2597        return null;
2598    }
2599
2600    /**
2601     * Export the result column names to the passed in String[].
2602     *
2603     * @param columnNames String[] to hold the column names.
2604     */

2605    public void exportNames(String JavaDoc[] columnNames)
2606    {
2607        if (SanityManager.DEBUG)
2608        {
2609            if (size() != columnNames.length)
2610            {
2611                SanityManager.THROWASSERT(
2612                    "size() (" +
2613                    size() +
2614                    ") is expected to equal columnNames.length (" +
2615                    columnNames.length +
2616                    ")");
2617            }
2618        }
2619
2620        int size = size();
2621
2622        for (int index = 0; index < size; index++)
2623        {
2624            columnNames[index] = ((ResultColumn) elementAt(index)).getName();
2625        }
2626    }
2627
2628    /**
2629     * Count the number of RCs with simple ColumnReferences.
2630     * (RC.expression instanceof ColumnReference) This is useful
2631     * for ensuring that the number of columns in the group by list
2632     * equals the number of grouping columns.
2633     *
2634     * @return int The number of simple ColumnReferences.
2635     */

2636    public int countNumberOfSimpleColumnReferences()
2637    {
2638        int numCRs = 0;
2639
2640        int size = size();
2641
2642        for (int index = 0; index < size; index++)
2643        {
2644            if (((ResultColumn) elementAt(index)).getExpression() instanceof ColumnReference)
2645            {
2646                numCRs++;
2647            }
2648        }
2649
2650        return numCRs;
2651    }
2652
2653    /**
2654     * Given a ResultColumn at the next deepest level in the tree,
2655     * search this RCL for its parent ResultColumn.
2656     *
2657     * @param childRC The child ResultColumn
2658     *
2659     * @return ResultColumn The parent ResultColumn
2660     */

2661    public ResultColumn findParentResultColumn(ResultColumn childRC)
2662    {
2663        ResultColumn parentRC = null;
2664
2665        int size = size();
2666
2667        for (int index = 0; index < size; index++)
2668        {
2669            ResultColumn rc = (ResultColumn) elementAt(index);
2670
2671            if (rc.getExpression() instanceof ColumnReference)
2672            {
2673                ColumnReference cr = (ColumnReference) rc.getExpression();
2674
2675                if (cr.getSource() == childRC)
2676                {
2677                    parentRC = rc;
2678                    break;
2679                }
2680            }
2681            else if (rc.getExpression() instanceof VirtualColumnNode)
2682            {
2683                VirtualColumnNode vcn = (VirtualColumnNode) rc.getExpression();
2684
2685                if (vcn.getSourceColumn() == childRC)
2686                {
2687                    parentRC = rc;
2688                    break;
2689                }
2690            }
2691
2692        }
2693
2694        return parentRC;
2695    }
2696
2697    public void setClause(int clause)
2698    {
2699        int size = size();
2700
2701        for (int index = 0; index < size; index++)
2702        {
2703            ResultColumn rc = (ResultColumn) elementAt(index);
2704            rc.setClause(clause);
2705        }
2706    }
2707
2708    /**
2709     * Mark as updatable all the columns in this result column list
2710     * that match the columns in the given update column list.
2711     *
2712     * @param updateColumns A ResultColumnList representing the columns
2713     * to be updated.
2714     */

2715    void markUpdated(ResultColumnList updateColumns)
2716    {
2717        ResultColumn updateColumn;
2718        ResultColumn resultColumn;
2719
2720        int size = updateColumns.size();
2721
2722        for (int index = 0; index < size; index++)
2723        {
2724            updateColumn = (ResultColumn) updateColumns.elementAt(index);
2725
2726            resultColumn = getResultColumn(updateColumn.getName());
2727
2728            /*
2729            ** This ResultColumnList may not be bound yet - for update
2730            ** statements, we mark the updated columns *before* we bind
2731            ** the RCL. This ordering is important because we add columns
2732            ** to the RCL after marking the update columns and before
2733            ** binding.
2734            **
2735            ** So, it can happen that there is an invalid column name in
2736            ** the list. This condition will cause an exception when the
2737            ** RCL is bound. Just ignore it for now.
2738            */

2739            if (resultColumn != null)
2740            {
2741                resultColumn.markUpdated();
2742            }
2743        }
2744    }
2745
2746    /**
2747     * Mark all the columns in the select sql that this result column list represents
2748     * as updatable if they match the columns in the given update column list.
2749     *
2750     * @param updateColumns A Vector representing the columns
2751     * to be updated.
2752     */

2753    void markColumnsInSelectListUpdatableByCursor(Vector JavaDoc updateColumns)
2754    {
2755        commonCodeForUpdatableByCursor(updateColumns, true);
2756    }
2757
2758    /**
2759     * dealingWithSelectResultColumnList true means we are dealing with
2760     * ResultColumnList for a select sql. When dealing with ResultColumnList for
2761     * select sql, it is possible that not all the updatable columns are
2762     * projected in the select column list and hence it is possible that we may
2763     * not find the column to be updated in the ResultColumnList and that is why
2764     * special handling is required when dealingWithSelectResultColumnList is true.
2765     * eg select c11, c13 from t1 for update of c11, c12
2766     * In the eg above, we will find updatable column c11 in the select column
2767     * list but we will not find updatable column c12 in the select column list
2768     */

2769    private void commonCodeForUpdatableByCursor(Vector JavaDoc updateColumns, boolean dealingWithSelectResultColumnList)
2770    {
2771        /*
2772        ** If there is no update column list, or the list is empty, then it means that
2773        ** all the columns which have a base table associated with them are updatable.
2774        */

2775        if ( (updateColumns == null) || (updateColumns.size() == 0) )
2776        {
2777            markUpdatableByCursor();
2778        }
2779        else
2780        {
2781            int ucSize = updateColumns.size();
2782            ResultColumn resultColumn;
2783            String JavaDoc columnName;
2784
2785            for (int index = 0; index < ucSize; index++)
2786            {
2787                columnName = (String JavaDoc) updateColumns.elementAt(index);
2788
2789                resultColumn = getResultColumn(columnName);
2790                if (SanityManager.DEBUG)
2791                {
2792                    if (resultColumn == null && !dealingWithSelectResultColumnList)
2793                    {
2794                        SanityManager.THROWASSERT("No result column found with name " +
2795                            columnName);
2796                    }
2797                }
2798                //Following if means the column specified in FOR UPDATE clause is not
2799
//part of the select list
2800
if (resultColumn == null && dealingWithSelectResultColumnList)
2801                    continue;
2802                resultColumn.markUpdatableByCursor();
2803            }
2804        }
2805    }
2806
2807    /**
2808     * Mark as updatable all the columns in this result column list
2809     * that match the columns in the given update column list
2810     *
2811     * @param updateColumns A Vector representing the columns
2812     * to be updated.
2813     */

2814    void markUpdatableByCursor(Vector JavaDoc updateColumns)
2815    {
2816        commonCodeForUpdatableByCursor(updateColumns, false);
2817    }
2818
2819    /**
2820     * Returns true if the given column position is for a column that will
2821     * be or could be updated by the positioned update of a cursor.
2822     *
2823     * @param columnPosition The position of the column in question
2824     *
2825     * @return true if the column is updatable
2826     */

2827    boolean updatableByCursor(int columnPosition)
2828    {
2829        return getResultColumn(columnPosition).updatableByCursor();
2830    }
2831
2832
2833    /**
2834     * Return whether or not this RCL can be flattened out of a tree.
2835     * It can only be flattened if the expressions are all cloneable.
2836     *
2837     * @return boolean Whether or not this RCL can be flattened out of a tree.
2838     */

2839    public boolean isCloneable()
2840    {
2841        boolean retcode = true;
2842        int size = size();
2843
2844        for (int index = 0; index < size; index++)
2845        {
2846            ResultColumn rc = (ResultColumn) elementAt(index);
2847
2848            if (! rc.getExpression().isCloneable())
2849            {
2850                retcode = false;
2851                break;
2852            }
2853        }
2854
2855        return retcode;
2856    }
2857
2858    /**
2859     * Remap all ColumnReferences in this tree to be clones of the
2860     * underlying expression.
2861     *
2862     * @exception StandardException Thrown on error
2863     */

2864    public void remapColumnReferencesToExpressions() throws StandardException
2865    {
2866        int size = size();
2867        for (int index = 0; index < size; index++)
2868        {
2869            ResultColumn rc = (ResultColumn) elementAt(index);
2870
2871            // The expression may be null if this column is an identity
2872
// column generated always. If the expression is not null, it
2873
// is a ColumnReference; we call through to the ColumnReference
2874
// to give it a chance to remap itself from the outer query
2875
// node to this one.
2876
if (rc.getExpression() != null)
2877                rc.setExpression(
2878                    rc.getExpression().remapColumnReferencesToExpressions());
2879        }
2880    }
2881
2882    /*
2883    ** Indicate that the conglomerate is an index, so we need to generate a
2884    ** RowLocation as the last column of the result set.
2885    **
2886    ** @param cid The conglomerate id of the index
2887    */

2888    void setIndexRow(long cid, boolean forUpdate)
2889    {
2890        indexRow = true;
2891        conglomerateId = cid;
2892        this.forUpdate = forUpdate;
2893    }
2894
2895    /* Debugging methods */
2896
2897    /**
2898     * Verify that all ResultColumns and their expressions have type information
2899     * and that the type information between the respective RCs and
2900     * expressions matches.
2901     *
2902     * @return boolean Whether or not the type information is consistent
2903     */

2904    public boolean hasConsistentTypeInfo() throws StandardException
2905    {
2906        boolean isConsistent = true;
2907
2908        if (SanityManager.DEBUG)
2909        {
2910        int size = size();
2911        for (int index = 0; index < size; index++)
2912            {
2913                ResultColumn rc = (ResultColumn) elementAt(index);
2914                ValueNode expr = rc.getExpression();
2915                DataTypeDescriptor rcDTS = rc.getTypeServices();
2916                DataTypeDescriptor exDTS = expr.getTypeServices();
2917
2918                if (rcDTS == null || exDTS == null)
2919                {
2920                    isConsistent = false;
2921                    break;
2922                }
2923
2924                if (rcDTS.getClass().getName() !=
2925                    exDTS.getClass().getName())
2926                {
2927                    isConsistent = false;
2928                    break;
2929                }
2930            }
2931        }
2932
2933        return isConsistent;
2934    }
2935
2936    /**
2937     * Return whether or not this RCL contains an AllResultColumn.
2938     * This is useful when dealing with SELECT * views which
2939     * reference tables that may have had columns added to them via
2940     * ALTER TABLE since the view was created.
2941     *
2942     * @return Whether or not this RCL contains an AllResultColumn.
2943     */

2944    public boolean containsAllResultColumn()
2945    {
2946        boolean containsAllResultColumn = false;
2947
2948        int size = size();
2949        for (int index = 0; index < size; index++)
2950        {
2951            if (elementAt(index) instanceof AllResultColumn)
2952            {
2953                containsAllResultColumn = true;
2954                break;
2955            }
2956        }
2957
2958        return containsAllResultColumn;
2959    }
2960
2961    /**
2962     * Count the number of RCs in the list that are referenced.
2963     *
2964     * @return The number of RCs in the list that are referenced.
2965     */

2966    public int countReferencedColumns()
2967    {
2968        int numReferenced = 0;
2969
2970        int size = size();
2971        for (int index = 0; index < size; index++)
2972        {
2973            ResultColumn rc = (ResultColumn) elementAt(index);
2974            if (rc.isReferenced())
2975            {
2976                numReferenced++;
2977            }
2978        }
2979        return numReferenced;
2980    }
2981
2982    /**
2983     * Record the column ids of the referenced columns in the specified array.
2984     *
2985     * @param idArray int[] for column ids
2986     * @param basis 0 (for 0-based ids) or 1 (for 1-based ids)
2987     */

2988    public void recordColumnReferences(int[] idArray, int basis)
2989    {
2990        int currArrayElement = 0;
2991        int size = size();
2992        for (int index = 0; index < size; index++)
2993        {
2994            ResultColumn rc = (ResultColumn) elementAt(index);
2995
2996            if (rc.isReferenced())
2997            {
2998                idArray[currArrayElement++] = index + basis;
2999            }
3000        }
3001    }
3002
3003    /**
3004     * Record the top level ColumnReferences in the specified array
3005     * and table map
3006     * This is useful when checking for uniqueness conditions.
3007     * NOTE: All top level CRs assumed to be from the same table.
3008     * The size of the array is expected to be the # of columns
3009     * in the table of interest + 1, so we use 1-base column #s.
3010     *
3011     * @param colArray1 boolean[] for columns
3012     * @param tableColMap JBitSet[] for tables
3013     * @param tableNumber Table number of column references
3014     */

3015    public void recordColumnReferences(boolean[] colArray1, JBitSet[] tableColMap,
3016            int tableNumber)
3017    {
3018        int size = size();
3019        for (int index = 0; index < size; index++)
3020        {
3021            int columnNumber;
3022            ResultColumn rc = (ResultColumn) elementAt(index);
3023
3024            if (! (rc.getExpression() instanceof ColumnReference))
3025            {
3026                continue;
3027            }
3028
3029            columnNumber = ((ColumnReference) rc.getExpression()).getColumnNumber();
3030            colArray1[columnNumber] = true;
3031            tableColMap[tableNumber].set(columnNumber);
3032        }
3033    }
3034
3035    /**
3036     * Return whether or not all of the RCs in the list whose
3037     * expressions are ColumnReferences are
3038     * from the same table. One place this
3039     * is useful for distinct elimination based on the existence
3040     * of a uniqueness condition.
3041     *
3042     * @return -1 if all of the top level CRs in the RCL
3043     * are not ColumnReferences from the same table,
3044     * else the tableNumber
3045     */

3046    int allTopCRsFromSameTable()
3047    {
3048        int tableNumber = -1;
3049
3050        int size = size();
3051        for (int index = 0; index < size; index++)
3052        {
3053            ResultColumn rc = (ResultColumn) elementAt(index);
3054            ValueNode vn = rc.getExpression();
3055            if (! (vn instanceof ColumnReference))
3056            {
3057                continue;
3058            }
3059
3060            // Remember the tableNumber from the first CR
3061
ColumnReference cr = (ColumnReference) vn;
3062            if (tableNumber == -1)
3063            {
3064                tableNumber = cr.getTableNumber();
3065            }
3066            else if (tableNumber != cr.getTableNumber())
3067            {
3068                return -1;
3069            }
3070        }
3071        return tableNumber;
3072    }
3073
3074    /**
3075     * Clear the column references from the RCL. (Restore RCL back to a state
3076     * where none of the RCs are marked as referenced.)
3077     */

3078    public void clearColumnReferences()
3079    {
3080        int size = size();
3081        for (int index = 0; index < size; index++)
3082        {
3083            ResultColumn rc = (ResultColumn) elementAt(index);
3084
3085            if (rc.isReferenced())
3086            {
3087                rc.setUnreferenced();
3088            }
3089        }
3090    }
3091
3092    /**
3093     * Copy the referenced RCs from this list to the supplied target list.
3094     *
3095     * @param targetList The list to copy to
3096     */

3097    public void copyReferencedColumnsToNewList(ResultColumnList targetList)
3098    {
3099        int size = size();
3100        for (int index = 0; index < size; index++)
3101        {
3102            ResultColumn rc = (ResultColumn) elementAt(index);
3103
3104            if (rc.isReferenced())
3105            {
3106                targetList.addElement(rc);
3107            }
3108        }
3109    }
3110
3111    /**
3112     * Copy the RCs from this list to the supplied target list.
3113     *
3114     * @param targetList The list to copy to,
3115     * @param copyList 1 based bitMap we copy columns associated with set bits.
3116     */

3117    public void copyColumnsToNewList(ResultColumnList targetList, FormatableBitSet copyList)
3118    {
3119        int size = size();
3120        for (int index = 0; index < size; index++)
3121        {
3122            ResultColumn rc = (ResultColumn) elementAt(index);
3123            if (copyList.isSet(rc.getColumnPosition()))
3124            {
3125                targetList.addElement(rc);
3126            }
3127        }
3128    }
3129
3130
3131    /**
3132     * Get a FormatableBitSet of the columns referenced in this rcl
3133     *
3134     * @return the FormatableBitSet
3135     */

3136    public FormatableBitSet getColumnReferenceMap()
3137    {
3138        FormatableBitSet colMap = new FormatableBitSet(size());
3139        int size = size();
3140        for (int index = 0; index < size; index++)
3141        {
3142            ResultColumn rc = (ResultColumn) elementAt(index);
3143            if (rc.isReferenced())
3144            {
3145                colMap.set(index);
3146            }
3147        }
3148        return colMap;
3149    }
3150
3151    /**
3152     * Or in any isReferenced booleans from the virtual column chain. That is the isReferenced bits on each
3153     * ResultColumn on the list will be set if the ResultColumn is referenced or if any VirtualColumnNode in its
3154     * expression chain refers to a referenced column.
3155     */

3156    void pullVirtualIsReferenced()
3157    {
3158        int size = size();
3159        for( int index = 0; index < size; index++)
3160        {
3161            ResultColumn rc = (ResultColumn) elementAt(index);
3162            rc.pullVirtualIsReferenced();
3163        }
3164    } // end of pullVirtualIsReferenced
3165

3166    public void clearTableNames()
3167    {
3168        int size = size();
3169        for (int index = 0; index < size; index++)
3170        {
3171            ResultColumn rc = (ResultColumn) elementAt(index);
3172            rc.clearTableName();
3173        }
3174    }
3175
3176    /**
3177     * Set the value of whether or not a count mismatch is allowed between
3178     * this RCL, as a derived column list, and an underlying RCL. This is allowed
3179     * for SELECT * views when an underlying table has had columns added to it
3180     * via ALTER TABLE.
3181     *
3182     * @param allowed Whether or not a mismatch is allowed.
3183     */

3184    protected void setCountMismatchAllowed(boolean allowed)
3185    {
3186        countMismatchAllowed = allowed;
3187    }
3188
3189    /**
3190     * Return whether or not a count mismatch is allowed between this RCL,
3191     * as a derived column list, and an underlying RCL. This is allowed
3192     * for SELECT * views when an underlying table has had columns added to it
3193     * via ALTER TABLE.
3194     *
3195     * return Whether or not a mismatch is allowed.
3196     */

3197
3198    protected boolean getCountMismatchAllowed()
3199    {
3200        return countMismatchAllowed;
3201    }
3202
3203    /**
3204     * Get the size of all the columns added
3205     * together. Does <B>NOT</B> include the
3206     * column overhead that the store requires.
3207     * Also, will be a very rough estimate for
3208     * user types.
3209     *
3210     * @return the size
3211     */

3212    public int getTotalColumnSize()
3213    {
3214        int colSize = 0;
3215        int size = size();
3216        for (int index = 0; index < size; index++)
3217        {
3218            colSize += ((ResultColumn) elementAt(index)).getMaximumColumnSize();
3219        }
3220        return colSize;
3221    }
3222
3223    /**
3224     * Generate an RCL to match the contents of a ResultSetMetaData.
3225     * This is useful when dealing with VTIs.
3226     *
3227     * @param rsmd The ResultSetMetaData.
3228     * @param tableName The TableName for the BCNs.
3229     * @param javaClassName The name of the VTI
3230     *
3231     * @exception StandardException Thrown on error
3232     */

3233    public void createListFromResultSetMetaData(ResultSetMetaData JavaDoc rsmd,
3234                                                TableName tableName,
3235                                                String JavaDoc javaClassName)
3236            throws StandardException
3237    {
3238        try
3239        {
3240            // JDBC columns #s are 1-based
3241
// Check to make sure # of columns >= 1
3242
int numColumns = rsmd.getColumnCount();
3243
3244            if (numColumns <= 0)
3245            {
3246                throw StandardException.newException(SQLState.LANG_INVALID_V_T_I_COLUMN_COUNT,
3247                                    javaClassName, String.valueOf(numColumns));
3248            }
3249
3250            for (int index = 1; index <= numColumns; index++)
3251            {
3252                boolean nullableResult =
3253                    (rsmd.isNullable(index) != ResultSetMetaData.columnNoNulls);
3254
3255                TypeId cti;
3256
3257                int jdbcColumnType = rsmd.getColumnType(index);
3258
3259                switch (jdbcColumnType) {
3260                case org.apache.derby.iapi.reference.JDBC20Translation.SQL_TYPES_JAVA_OBJECT:
3261                case Types.OTHER:
3262                {
3263                    cti = TypeId.getUserDefinedTypeId(rsmd.getColumnTypeName(index), false);
3264                    break;
3265                }
3266                default:
3267                {
3268                    cti = TypeId.getBuiltInTypeId(jdbcColumnType);
3269                    break;
3270                }
3271                }
3272
3273                // Handle the case where a VTI returns a bad column type
3274
if (cti == null)
3275                {
3276                    throw StandardException.newException(SQLState.LANG_BAD_J_D_B_C_TYPE_INFO, Integer.toString(index));
3277                }
3278
3279                // Get the maximum byte storage for this column
3280
int maxWidth;
3281
3282                /* Get maximum byte storage from rsmd for variable
3283                 * width types, set it to MAXINT for the long types,
3284                 * otherwise get it from the TypeId
3285                 */

3286                if (cti.variableLength())
3287                {
3288                    maxWidth = rsmd.getColumnDisplaySize(index);
3289                }
3290                else if (jdbcColumnType == Types.LONGVARCHAR ||
3291                         jdbcColumnType == Types.LONGVARBINARY)
3292                {
3293                    maxWidth = Integer.MAX_VALUE;
3294                }
3295                else
3296                {
3297                    maxWidth = 0;
3298                }
3299
3300                int precision = cti.isDecimalTypeId() ? rsmd.getPrecision(index) : 0;
3301                int scale = cti.isDecimalTypeId() ? rsmd.getScale(index) : 0;
3302                DataTypeDescriptor dts = new DataTypeDescriptor(cti,
3303                                            precision,
3304                                            scale,
3305                                            nullableResult,
3306                                            maxWidth);
3307                ValueNode bcn = (ValueNode) getNodeFactory().getNode(
3308                                            C_NodeTypes.BASE_COLUMN_NODE,
3309                                            rsmd.getColumnName(index),
3310                                            tableName,
3311                                            dts,
3312                                            getContextManager());
3313                ResultColumn rc = (ResultColumn) getNodeFactory().getNode(
3314                                        C_NodeTypes.RESULT_COLUMN,
3315                                        rsmd.getColumnName(index),
3316                                        bcn,
3317                                        getContextManager());
3318                rc.setType(dts);
3319                addResultColumn(rc);
3320            }
3321        }
3322        catch (Throwable JavaDoc t)
3323        {
3324            if (t instanceof StandardException)
3325            {
3326                throw (StandardException) t;
3327            }
3328            else
3329            {
3330                throw StandardException.unexpectedUserException(t);
3331            }
3332        }
3333    }
3334
3335    /**
3336     * Add an RC to the end of the list for the RID from an index.
3337     * NOTE: RC.expression is a CurrentRowLocationNode. This was previously only used
3338     * for non-select DML. We test for this node when generating the holder above
3339     * and generate the expected code. (We really should create yet another new node
3340     * type with its own code generation.)
3341     *
3342     * @exception StandardException Thrown on error
3343     */

3344    public void addRCForRID()
3345        throws StandardException
3346    {
3347        ResultColumn rowLocationColumn;
3348        CurrentRowLocationNode rowLocationNode;
3349
3350        /* Generate the RowLocation column */
3351        rowLocationNode = (CurrentRowLocationNode) getNodeFactory().getNode(
3352                                        C_NodeTypes.CURRENT_ROW_LOCATION_NODE,
3353                                        getContextManager());
3354        rowLocationColumn =
3355                (ResultColumn) getNodeFactory().getNode(
3356                                    C_NodeTypes.RESULT_COLUMN,
3357                                    "",
3358                                    rowLocationNode,
3359                                    getContextManager());
3360        rowLocationColumn.markGenerated();
3361
3362        /* Append to the ResultColumnList */
3363        addResultColumn(rowLocationColumn);
3364    }
3365
3366    /**
3367     * Walk the list and mark all RCs as unreferenced. This is useful
3368     * when recalculating which RCs are referenced at what level like
3369     * when deciding which columns need to be returned from a non-matching
3370     * index scan (as opposed to those returned from the base table).
3371     *
3372     * @exception StandardException Thrown on error
3373     */

3374    public void markAllUnreferenced()
3375                throws StandardException
3376    {
3377        int size = size();
3378
3379        for (int index = 0; index < size; index++)
3380        {
3381            ResultColumn resultColumn = (ResultColumn) elementAt(index);
3382            resultColumn.setUnreferenced();
3383        }
3384    }
3385
3386    /**
3387     * Determine if all of the RC.expressions are columns in the source result set.
3388     * This is useful for determining if we need to do reflection
3389     * at execution time.
3390     *
3391     * @param sourceRS The source ResultSet.
3392     *
3393     * @return Whether or not all of the RC.expressions are columns in the source result set.
3394     */

3395    boolean allExpressionsAreColumns(ResultSetNode sourceRS)
3396    {
3397        int size = size();
3398
3399        for (int index = 0; index < size; index++)
3400        {
3401            ResultColumn resultColumn;
3402            ValueNode expr;
3403
3404            resultColumn = (ResultColumn) elementAt(index);
3405            expr = resultColumn.getExpression();
3406            if (! (expr instanceof VirtualColumnNode) &&
3407                ! (expr instanceof ColumnReference))
3408            {
3409                return false;
3410            }
3411
3412            /* If the expression is a VirtualColumnNode, make sure that the column
3413             * is coming from the source result set, ie, that it is not a correlated
3414             * column.
3415             */

3416            if (expr instanceof VirtualColumnNode)
3417            {
3418                VirtualColumnNode vcn = (VirtualColumnNode) expr;
3419                if (vcn.getSourceResultSet() != sourceRS)
3420                {
3421                    vcn.setCorrelated();
3422                    return false;
3423                }
3424            }
3425
3426            /* Make sure this is not a correlated CR */
3427            if (expr instanceof ColumnReference)
3428            {
3429                ColumnReference cr = (ColumnReference) expr;
3430                if (cr.getCorrelated())
3431                {
3432                    return false;
3433                }
3434            }
3435        }
3436        return true;
3437    }
3438
3439    /**
3440     * Map the source columns to these columns. Build an array to represent the mapping.
3441     * For each RC, if the expression is simply a VCN or a CR then set the array element to be
3442     * the virtual column number of the source RC. Otherwise, set the array element to
3443     * -1.
3444     * This is useful for determining if we need to do reflection
3445     * at execution time.
3446     *
3447     * @return Array representiong mapping of RCs to source RCs.
3448     */

3449    int[] mapSourceColumns()
3450    {
3451        int[] mapArray = new int[size()];
3452        ResultColumn resultColumn;
3453
3454        int size = size();
3455
3456        for (int index = 0; index < size; index++)
3457        {
3458            resultColumn = (ResultColumn) elementAt(index);
3459            if (resultColumn.getExpression() instanceof VirtualColumnNode)
3460            {
3461                VirtualColumnNode vcn = (VirtualColumnNode) resultColumn.getExpression();
3462
3463                // Can't deal with correlated VCNs
3464
if (vcn.getCorrelated())
3465                {
3466                    mapArray[index] = -1;
3467                }
3468                else
3469                {
3470                    // Virtual column #s are 1-based
3471
mapArray[index] = vcn.getSourceColumn().getVirtualColumnId();
3472                }
3473            }
3474            else if (resultColumn.getExpression() instanceof ColumnReference)
3475            {
3476                ColumnReference cr = (ColumnReference) resultColumn.getExpression();
3477
3478                // Can't deal with correlated CRs
3479
if (cr.getCorrelated())
3480                {
3481                    mapArray[index] = -1;
3482                }
3483                else
3484                {
3485                    // Virtual column #s are 1-based
3486
mapArray[index] = cr.getSource().getVirtualColumnId();
3487                }
3488            }
3489            else
3490            {
3491                mapArray[index] = -1;
3492            }
3493        }
3494
3495        return mapArray;
3496    }
3497
3498    /** Set the nullability of every ResultColumn in this list */
3499    public void setNullability(boolean nullability)
3500    {
3501        int size = size();
3502
3503        for (int index = 0; index < size; index++)
3504        {
3505            ResultColumn resultColumn = (ResultColumn) elementAt(index);
3506            resultColumn.setNullability(nullability);
3507        }
3508    }
3509
3510    /**
3511     * Generate a FormatableBitSet representing the columns that are referenced in this RCL.
3512     * The caller decides if they want this FormatableBitSet if every RC is referenced.
3513     *
3514     * @param positionedUpdate Whether or not the scan that the RCL
3515     * belongs to is for update w/o a column list
3516     * @param always Whether or not caller always wants a non-null FormatableBitSet if
3517     * all RCs are referenced.
3518     * @param onlyBCNs If true, only set bit if expression is a BaseColumnNode,
3519     * otherwise set bit for all referenced RCs.
3520     *
3521     * @return The FormatableBitSet representing the referenced RCs.
3522    */

3523
3524    FormatableBitSet getReferencedFormatableBitSet(boolean positionedUpdate, boolean always, boolean onlyBCNs)
3525    {
3526        int index;
3527        int colsAdded = 0;
3528        int size = size();
3529
3530        FormatableBitSet newReferencedCols = new FormatableBitSet(size);
3531
3532        /*
3533        ** For an updatable cursor, we need
3534        ** all columns.
3535        */

3536        if (positionedUpdate)
3537        {
3538            if (always)
3539            {
3540                /* Set all bits in the bit map */
3541                for (index = 0; index < size; index++)
3542                {
3543                    newReferencedCols.set(index);
3544                }
3545
3546                return newReferencedCols;
3547            }
3548            else
3549            {
3550                return null;
3551            }
3552        }
3553    
3554        for (index = 0; index < size; index++)
3555        {
3556            ResultColumn oldCol = (ResultColumn) elementAt(index);
3557            if (oldCol.isReferenced())
3558            {
3559                /* Skip RCs whose expression is not a BCN
3560                 * when requested to do so.
3561                 */

3562                if (onlyBCNs && ! (oldCol.getExpression() instanceof BaseColumnNode))
3563                {
3564                    continue;
3565                }
3566                newReferencedCols.set(index);
3567                colsAdded++;
3568            }
3569        }
3570
3571        /* Return the FormatableBitSet if not all RCs are referenced or if
3572         * the caller always wants the FormatableBitSet returned.
3573         */

3574        if (colsAdded != index || always)
3575        {
3576            return newReferencedCols;
3577        }
3578        else
3579        {
3580            return null;
3581        }
3582    }
3583
3584    /**
3585     * Create a new, compacted RCL based on the referenced RCs
3586     * in this list. If the RCL being compacted is for an
3587     * updatable scan, then we simply return this.
3588     *
3589     * The caller tells us whether or not they want a new list
3590     * if there is no compaction because all RCs are referenced.
3591     * This is useful in the case where the caller needs a new
3592     * RCL for existing RCs so that it can augment the new list.
3593     *
3594     * @param positionedUpdate Whether or not the scan that the RCL
3595     * belongs to is for update w/o a column list
3596     * @param always Whether or not caller always wants a new RCL
3597     *
3598     * @return The compacted RCL if compaction occurred, otherwise return this RCL.
3599     *
3600     * @exception StandardException Thrown on error
3601     */

3602    ResultColumnList compactColumns(boolean positionedUpdate, boolean always)
3603        throws StandardException
3604    {
3605        int index;
3606        int colsAdded = 0;
3607
3608        /*
3609        ** For an updatable cursor, we need
3610        ** all columns.
3611        */

3612        if (positionedUpdate)
3613        {
3614            return this;
3615        }
3616    
3617        ResultColumnList newCols = (ResultColumnList) getNodeFactory().getNode(
3618                                                C_NodeTypes.RESULT_COLUMN_LIST,
3619                                                getContextManager());
3620
3621        int size = size();
3622        for (index = 0; index < size; index++)
3623        {
3624            ResultColumn oldCol = (ResultColumn) elementAt(index);
3625            if (oldCol.isReferenced())
3626            {
3627                newCols.addResultColumn(oldCol);
3628                colsAdded++;
3629            }
3630        }
3631
3632        /* Return new RCL if we found unreferenced columns or if
3633         * the caller always wants a new list.
3634         */

3635        if (colsAdded != index || always)
3636        {
3637            return newCols;
3638        }
3639        else
3640        {
3641            return this;
3642        }
3643    }
3644
3645    /**
3646     * Remove the columns which are join columns (in the
3647     * joinColumns RCL) from this list. This is useful
3648     * for a JOIN with a USING clause.
3649     *
3650     * @param joinColumns The list of join columns
3651     */

3652    void removeJoinColumns(ResultColumnList joinColumns)
3653    {
3654        int jcSize = joinColumns.size();
3655        for (int index = 0; index < jcSize; index++)
3656        {
3657            ResultColumn joinRC = (ResultColumn) joinColumns.elementAt(index);
3658            String JavaDoc columnName = joinRC.getName();
3659
3660            // columnName should always be non-null
3661
if (SanityManager.DEBUG)
3662            {
3663                SanityManager.ASSERT(columnName != null,
3664                    "columnName should be non-null");
3665            }
3666
3667            ResultColumn rightRC = getResultColumn(columnName);
3668
3669            // Remove the RC from this list.
3670
if (rightRC != null)
3671            {
3672                removeElement(rightRC);
3673            }
3674        }
3675    }
3676
3677    /**
3678     * Get the join columns from this list.
3679     * This is useful for a join with a USING clause.
3680     * (ANSI specifies that the join columns appear 1st.)
3681     *
3682     * @param joinColumns A list of the join columns.
3683     *
3684     * @return A list of the join columns from this list
3685     */

3686    ResultColumnList getJoinColumns(ResultColumnList joinColumns)
3687    {
3688        ResultColumnList newRCL = new ResultColumnList();
3689
3690        /* Find all of the join columns and put them 1st on the
3691         * new RCL.
3692         */

3693        int jcSize = joinColumns.size();
3694        for (int index = 0; index < jcSize; index++)
3695        {
3696            ResultColumn joinRC = (ResultColumn) joinColumns.elementAt(index);
3697            String JavaDoc columnName = joinRC.getName();
3698
3699            // columnName should always be non-null
3700
if (SanityManager.DEBUG)
3701            {
3702                SanityManager.ASSERT(columnName != null,
3703                    "columnName should be non-null");
3704            }
3705
3706            ResultColumn xferRC = getResultColumn(columnName);
3707
3708            // Add the RC to the new list.
3709
newRCL.addElement(xferRC);
3710        }
3711        return newRCL;
3712    }
3713
3714    /**
3715     * Reset the virtual column ids for all of the
3716     * underlying RCs. (Virtual column ids are 1-based.)
3717     */

3718    void resetVirtualColumnIds()
3719    {
3720        int size = size();
3721
3722        for (int index = 0; index < size; index++)
3723        {
3724            /* ResultColumns are 1-based */
3725            ((ResultColumn) elementAt(index)).setVirtualColumnId(index + 1);
3726        }
3727    }
3728
3729    /**
3730     * Return whether or not the same result row can be used for all
3731     * rows returned by the associated ResultSet. This is possible
3732     * if all entries in the list are constants or AggregateNodes.
3733     *
3734     * @return Whether or not the same result row can be used for all
3735     * rows returned by the associated ResultSet.
3736     */

3737    boolean reusableResult()
3738    {
3739        int size = size();
3740
3741        for (int index = 0; index < size; index++)
3742        {
3743            ResultColumn rc = (ResultColumn) elementAt(index);
3744
3745            if ((rc.getExpression() instanceof ConstantNode) ||
3746                (rc.getExpression() instanceof AggregateNode))
3747            {
3748                continue;
3749            }
3750            return false;
3751        }
3752        return true;
3753    }
3754
3755    /**
3756     * Get an array of column positions (1-based) for all the columns
3757     * in this RCL. Assumes that all the columns are in the passed-in
3758     * table
3759     *
3760     * @return the array of strings
3761     *
3762     * @exception throws StandardException on error
3763     */

3764    public int[] getColumnPositions( TableDescriptor td )
3765        throws StandardException
3766    {
3767        int size = size();
3768        int[] myPositions = new int[ size ];
3769        String JavaDoc columnName;
3770        ColumnDescriptor cd;
3771
3772        for ( int index = 0; index < size; index++ )
3773        {
3774            ResultColumn resultColumn = (ResultColumn) elementAt( index );
3775            columnName = resultColumn.getName();
3776            cd = td.getColumnDescriptor( columnName );
3777
3778            if ( cd == null )
3779            {
3780                throw StandardException.newException
3781                    ( SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, columnName, td.getQualifiedName() );
3782            }
3783
3784            myPositions[ index ] = cd.getPosition();
3785        }
3786
3787        return myPositions;
3788    }
3789
3790    /**
3791     * Get an array of strings for all the columns
3792     * in this RCL.
3793     *
3794     * @return the array of strings
3795     */

3796    public String JavaDoc[] getColumnNames()
3797    {
3798        String JavaDoc strings[] = new String JavaDoc[size()];
3799
3800        int size = size();
3801
3802        for (int index = 0; index < size; index++)
3803        {
3804            ResultColumn resultColumn = (ResultColumn) elementAt(index);
3805            strings[index] = resultColumn.getName();
3806        }
3807        return strings;
3808    }
3809
3810    /**
3811     * Replace any DEFAULTs with the associated tree for the default.
3812     *
3813     * @param ttd The TableDescriptor for the target table.
3814     * @param tcl The RCL for the target table.
3815     *
3816     * @exception StandardException Thrown on error
3817     */

3818    void replaceDefaults(TableDescriptor ttd, ResultColumnList tcl)
3819        throws StandardException
3820    {
3821        int size = size();
3822
3823        for (int index = 0; index < size; index++)
3824        {
3825            ResultColumn rc = (ResultColumn) elementAt(index);
3826
3827            if (rc.isDefaultColumn())
3828            {
3829                // DefaultNode defaultNode = (DefaultNode) rc.getExpression();
3830
// Get ColumnDescriptor by name or by position?
3831
ColumnDescriptor cd;
3832                if (tcl == null)
3833                {
3834                    cd = ttd.getColumnDescriptor(index + 1);
3835                }
3836                else
3837                {
3838                    ResultColumn trc = (ResultColumn) tcl.elementAt(index);
3839                    cd = ttd.getColumnDescriptor(trc.getName());
3840                }
3841
3842                // Too many RCs if no ColumnDescriptor
3843
if (cd == null)
3844                {
3845                    throw StandardException.newException(SQLState.LANG_TOO_MANY_RESULT_COLUMNS,
3846                                    ttd.getQualifiedName());
3847                }
3848
3849                if (cd.isAutoincrement())
3850                {
3851                    rc.setAutoincrementGenerated();
3852                } // end of if ()
3853

3854                DefaultInfoImpl defaultInfo = (DefaultInfoImpl) cd.getDefaultInfo();
3855                if (defaultInfo != null)
3856                {
3857                    /* Query is dependent on the DefaultDescriptor */
3858                    DefaultDescriptor defaultDescriptor = cd.getDefaultDescriptor(getDataDictionary());
3859                    getCompilerContext().createDependency(defaultDescriptor);
3860
3861                    rc.setExpression(
3862                        DefaultNode.parseDefault(
3863                            defaultInfo.getDefaultText(),
3864                            getLanguageConnectionContext(),
3865                            getCompilerContext()));
3866
3867                }
3868                else
3869                {
3870                    rc.setExpression(
3871                        (ValueNode) getNodeFactory().getNode(
3872                                        C_NodeTypes.UNTYPED_NULL_CONSTANT_NODE,
3873                                        getContextManager()));
3874                }
3875                rc.setDefaultColumn(false);
3876            }
3877        }
3878    }
3879
3880    /**
3881     * Walk the RCL and check for DEFAULTs. DEFAULTs
3882     * are invalid at the time that this method is called,
3883     * so we throw an exception if found.
3884     * NOTE: The grammar allows:
3885     * VALUES DEFAULT;
3886     *
3887     * @exception StandardException Thrown on error
3888     */

3889    void checkForInvalidDefaults()
3890        throws StandardException
3891    {
3892        int size = size();
3893
3894        for (int index = 0; index < size; index++)
3895        {
3896            ResultColumn rc = (ResultColumn) elementAt(index);
3897
3898            if (rc.isAutoincrementGenerated())
3899                continue;
3900
3901            if (rc.isDefaultColumn())
3902            {
3903                throw StandardException.newException(SQLState.LANG_INVALID_USE_OF_DEFAULT);
3904            }
3905        }
3906    }
3907
3908    /**
3909     * Verify that all of the RCs in this list are comparable.
3910     *
3911     * @exception StandardException Thrown on error
3912     */

3913    void verifyAllOrderable()
3914        throws StandardException
3915    {
3916        int size = size();
3917
3918        for (int index = 0; index < size; index++)
3919        {
3920            ResultColumn rc = (ResultColumn) elementAt(index);
3921            rc.verifyOrderable();
3922        }
3923    }
3924
3925    /**
3926      * Build this ResultColumnList from a table description and
3927      * an array of column IDs.
3928      *
3929      * @param table describes the table
3930      * @param columnIDs column positions in that table (1-based)
3931      *
3932      * @exception StandardException Thrown on error
3933      */

3934    public void populate
3935    (
3936        TableDescriptor table,
3937        int[] columnIDs
3938    )
3939        throws StandardException
3940    {
3941        if ( columnIDs == null ) { return; }
3942
3943        int count = columnIDs.length;
3944        TableName tableName = makeTableName( table.getSchemaName(), table.getName() );
3945        String JavaDoc columnName;
3946        int columnPosition;
3947        ResultColumn rc;
3948
3949        for ( int i = 0; i < count; i++ )
3950        {
3951            columnPosition = columnIDs[ i ];
3952            columnName = table.getColumnDescriptor( columnPosition ).getColumnName();
3953
3954            rc = makeColumnFromName( columnName );
3955
3956            addResultColumn( rc );
3957        }
3958
3959    }
3960
3961    private ResultColumn makeColumnFromName( String JavaDoc columnName )
3962        throws StandardException
3963    {
3964        ResultColumn resultColumn = (ResultColumn) getNodeFactory().getNode
3965            (
3966                C_NodeTypes.RESULT_COLUMN,
3967                columnName,
3968                null,
3969                getContextManager()
3970            );
3971
3972        return resultColumn;
3973    }
3974
3975    private ResultColumn makeColumnReferenceFromName
3976    (
3977        TableName tableName,
3978        String JavaDoc columnName
3979    )
3980        throws StandardException
3981    {
3982        ContextManager cm = getContextManager();
3983        NodeFactory nodeFactory = getNodeFactory();
3984
3985        ResultColumn rc = (ResultColumn) nodeFactory.getNode
3986            (
3987                C_NodeTypes.RESULT_COLUMN,
3988                null,
3989                nodeFactory.getNode
3990                (
3991                    C_NodeTypes.COLUMN_REFERENCE,
3992                    columnName,
3993                    tableName,
3994                    cm
3995                ),
3996                cm
3997            );
3998
3999        return rc;
4000    }
4001    
4002    /**
4003     * check if any autoincrement columns exist in the result column list.
4004     * called from insert or update where you cannot insert/update the value
4005     * of an autoincrement column.
4006     *
4007     * @exception StandardException If the column is an ai column
4008     */

4009    public void checkAutoincrement(ResultColumnList sourceRSRCL)
4010        throws StandardException
4011    {
4012        int size = size();
4013
4014        for (int index = 0; index < size; index++)
4015        {
4016            ResultColumn rc = (ResultColumn) elementAt(index);
4017            ResultColumn sourceRC =
4018                (ResultColumn)((sourceRSRCL == null) ? null : sourceRSRCL.elementAt(index));
4019            ColumnDescriptor cd = rc.getTableColumnDescriptor();
4020            
4021            if ((cd != null) && (cd.isAutoincrement()))
4022            {
4023                if ((sourceRC != null) &&
4024                    (sourceRC.isAutoincrementGenerated()))
4025                {
4026                    sourceRC.setColumnDescriptor(cd.getTableDescriptor(), cd);
4027
4028                }else{
4029                    if(cd.isAutoincAlways())
4030                        throw StandardException.newException(SQLState.LANG_AI_CANNOT_MODIFY_AI,
4031                                    rc.getName());
4032                }
4033            }
4034        }
4035    }
4036
4037    public void incOrderBySelect()
4038    {
4039        orderBySelect++;
4040    }
4041
4042    public void decOrderBySelect()
4043    {
4044        orderBySelect--;
4045    }
4046
4047    public int getOrderBySelect()
4048    {
4049        return orderBySelect;
4050    }
4051
4052    public void copyOrderBySelect( ResultColumnList src)
4053    {
4054        orderBySelect = src.orderBySelect;
4055    }
4056
4057    /* ****
4058     * Take note of the size of this RCL _before_ we start
4059     * processing/binding it. This is so that, at bind time,
4060     * we can tell if any columns in the RCL were added
4061     * internally by us (i.e. they were not specified by the
4062     * user and thus will not be returned to the user).
4063     */

4064    protected void markInitialSize() {
4065        initialListSize = size();
4066    }
4067}
4068
Popular Tags