KickJava   Java API By Example, From Geeks To Geeks.

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


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

21
22 package org.apache.derby.impl.sql.compile;
23
24 import org.apache.derby.iapi.services.compiler.MethodBuilder;
25
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27 import org.apache.derby.iapi.services.context.ContextManager;
28
29 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
30
31 import org.apache.derby.iapi.types.DataTypeDescriptor;
32 import org.apache.derby.iapi.types.DataValueDescriptor;
33 import org.apache.derby.iapi.types.StringDataValue;
34 import org.apache.derby.iapi.sql.ResultColumnDescriptor;
35 import org.apache.derby.iapi.types.DataTypeDescriptor;
36 import org.apache.derby.iapi.types.DataValueDescriptor;
37 import org.apache.derby.iapi.types.TypeId;
38 import org.apache.derby.iapi.services.io.StoredFormatIds;
39 import org.apache.derby.iapi.types.DataValueFactory;
40
41 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
42 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
43 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
44
45 import org.apache.derby.iapi.sql.compile.CompilerContext;
46 import org.apache.derby.iapi.sql.compile.RowOrdering;
47 import org.apache.derby.iapi.sql.compile.Visitable;
48 import org.apache.derby.iapi.sql.compile.Visitor;
49 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
50
51 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
52 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
53
54 import org.apache.derby.iapi.store.access.Qualifier;
55
56 import org.apache.derby.iapi.error.StandardException;
57 import org.apache.derby.iapi.reference.SQLState;
58 import org.apache.derby.iapi.reference.ClassName;
59
60 import org.apache.derby.iapi.util.JBitSet;
61 import org.apache.derby.iapi.util.StringUtil;
62
63 import java.sql.Types JavaDoc;
64
65 import java.util.Vector JavaDoc;
66
67 /**
68  * A ResultColumn represents a result column in a SELECT, INSERT, or UPDATE
69  * statement. In a SELECT statement, the result column just represents an
70  * expression in a row being returned to the client. For INSERT and UPDATE
71  * statements, the result column represents an column in a stored table.
72  * So, a ResultColumn has to be bound differently depending on the type of
73  * statement it appears in.
74  *
75  * @author Jeff Lichtman
76  */

77
78 public class ResultColumn extends ValueNode
79                 implements ResultColumnDescriptor, Comparable JavaDoc
80 {
81     /* name and exposedName should point to the same string, unless there is a
82      * derived column list, in which case name will point to the underlying name
83      * and exposedName will point to the name from the derived column list.
84      */

85     String JavaDoc name;
86     String JavaDoc exposedName;
87     String JavaDoc tableName;
88     String JavaDoc sourceTableName;
89     //Used by metadata api ResultSetMetaData.getSchemaName to get a column's table's schema.
90
String JavaDoc sourceSchemaName;
91     ValueNode expression;
92     ColumnDescriptor columnDescriptor;
93     boolean isGenerated;
94     boolean isGeneratedForUnmatchedColumnInInsert;
95     boolean isGroupingColumn;
96     boolean isReferenced;
97     boolean isRedundant;
98     boolean isNameGenerated;
99     boolean updated;
100     boolean updatableByCursor;
101     private boolean defaultColumn;
102
103     // tells us if this ResultColumn is a placeholder for a generated
104
// autoincrement value for an insert statement.
105
boolean autoincrementGenerated;
106
107     // tells us if this ResultColumn represents an autoincrement column in a
108
// base table.
109
boolean autoincrement;
110
111     /* ResultSetNumber for the ResultSet (at generate() time) that we belong to */
112     private int resultSetNumber = -1;
113     ColumnReference reference; // used to verify quals at bind time, if given.
114

115     /* virtualColumnId is the ResultColumn's position (1-based) within the ResultSet */
116     private int virtualColumnId;
117
118     /**
119      * Different types of initializer parameters indicate different
120      * types of initialization. Parameters may be:
121      *
122      * <ul>
123      * <li>arg1 The name of the column, if any.</li>
124      * <li>arg2 The expression this result column represents</li>
125      * </ul>
126      *
127      * <p>
128      * - OR -
129      * </p>
130      *
131      * <ul>
132      * <li>arg1 a column reference node</li>
133      * <li>arg2 The expression this result column represents</li>
134      * </ul>
135      *
136      * <p>
137      * - OR -
138      * </p>
139      *
140      * <ul>
141      * <li>arg1 The column descriptor.</li>
142      * <li>arg2 The expression this result column represents</li>
143      * </ul>
144      *
145      * <p>
146      * - OR -
147      * </p>
148      *
149      * <ul>
150      * <li>dtd The type of the column</li>
151      * <li>expression The expression this result column represents</li>
152      * </ul>
153      */

154     public void init(Object JavaDoc arg1, Object JavaDoc arg2) throws StandardException
155     {
156         // RESOLVE: This is something of a hack - it is not obvious that
157
// the first argument being null means it should be treated as
158
// a String.
159
if ((arg1 instanceof String JavaDoc) || (arg1 == null))
160         {
161             this.name = (String JavaDoc) arg1;
162             this.exposedName = this.name;
163             this.expression = (ValueNode) arg2;
164         }
165         else if (arg1 instanceof ColumnReference)
166         {
167             ColumnReference ref = (ColumnReference) arg1;
168
169             this.name = ref.getColumnName();
170             this.exposedName = ref.getColumnName();
171             /*
172                 when we bind, we'll want to make sure
173                 the reference has the right table name.
174             */

175             this.reference = ref;
176             this.expression = (ValueNode) arg2;
177         }
178         else if (arg1 instanceof ColumnDescriptor)
179         {
180             ColumnDescriptor coldes = (ColumnDescriptor) arg1;
181             DataTypeDescriptor colType = coldes.getType();
182
183             this.name = coldes.getColumnName();
184             this.exposedName = name;
185             /* Clone the type info here, so we can change nullability if needed */
186             setType(new DataTypeDescriptor(colType, colType.isNullable()));
187             this.columnDescriptor = coldes;
188             this.expression = (ValueNode) arg2;
189             this.autoincrement = coldes.isAutoincrement();
190         }
191         else
192         {
193             setType((DataTypeDescriptor) arg1);
194             this.expression = (ValueNode) arg2;
195             if (arg2 instanceof ColumnReference)
196             {
197                 reference = (ColumnReference) arg2;
198             }
199         }
200         
201         /* this result column represents a <default> keyword in an insert or
202          * update statement
203          */

204         if (expression != null &&
205             expression.isInstanceOf(C_NodeTypes.DEFAULT_NODE))
206             defaultColumn = true;
207     }
208
209     /**
210      * Returns TRUE if the ResultColumn is standing in for a DEFAULT keyword in
211      * an insert/update statement.
212      */

213     public boolean isDefaultColumn()
214     {
215         return defaultColumn;
216     }
217
218     public void setDefaultColumn(boolean value)
219     {
220         defaultColumn = value;
221     }
222
223     /**
224      * The following methods implement the ResultColumnDescriptor
225      * interface. See the Language Module Interface for details.
226      */

227
228     public String JavaDoc getName()
229     {
230         return exposedName;
231     }
232
233     public String JavaDoc getSchemaName() throws StandardException
234     {
235         if ((columnDescriptor!=null) &&
236             (columnDescriptor.getTableDescriptor() != null))
237             return columnDescriptor.getTableDescriptor().getSchemaName();
238         else
239         {
240             if (expression != null)
241             // REMIND: could look in reference, if set.
242
return expression.getSchemaName();
243             else
244                 return null;
245         }
246     }
247
248     public String JavaDoc getTableName()
249     {
250         if (tableName != null)
251         {
252             return tableName;
253         }
254         if ((columnDescriptor!=null) &&
255             (columnDescriptor.getTableDescriptor() != null))
256         {
257             return columnDescriptor.getTableDescriptor().getName();
258         }
259         else
260         {
261             return expression.getTableName();
262         }
263     }
264
265     /**
266      * @see ResultColumnDescriptor#getSourceTableName
267      */

268     public String JavaDoc getSourceTableName()
269     {
270         return sourceTableName;
271     }
272
273     /**
274      * @see ResultColumnDescriptor#getSourceSchemaName
275      */

276     public String JavaDoc getSourceSchemaName()
277     {
278         return sourceSchemaName;
279     }
280
281     /**
282      * Clear the table name for the underlying ColumnReference.
283      * See UpdateNode.scrubResultColumns() for full explaination.
284      */

285     public void clearTableName()
286     {
287         if (expression instanceof ColumnReference)
288         {
289             ((ColumnReference) expression).setTableNameNode((TableName) null);
290         }
291     }
292
293     public DataTypeDescriptor getType()
294     {
295         return dataTypeServices;
296     }
297
298     public DataTypeDescriptor getExpressionType() throws StandardException
299     {
300         return (expression == null) ?
301             dataTypeServices :
302             expression.getTypeServices();
303     }
304
305     public int getColumnPosition()
306     {
307         if (columnDescriptor!=null)
308             return columnDescriptor.getPosition();
309         else
310             return virtualColumnId;
311
312     }
313
314     /**
315      * Set the expression in this ResultColumn. This is useful in those
316      * cases where you don't know the expression in advance, like for
317      * INSERT statements with column lists, where the column list and
318      * SELECT or VALUES clause are parsed separately, and then have to
319      * be hooked up.
320      *
321      * @param expression The expression to be set in this ResultColumn
322      */

323
324     public void setExpression(ValueNode expression)
325     {
326         this.expression = expression;
327     }
328
329     /**
330      * Get the expression in this ResultColumn.
331      *
332      * @return ValueNode this.expression
333      */

334
335     public ValueNode getExpression()
336     {
337         return expression;
338     }
339
340     /**
341      * Set the expression to a null node of the
342      * correct type.
343      *
344      * @exception StandardException Thrown on error
345      */

346     void setExpressionToNullNode()
347         throws StandardException
348     {
349         expression = getNullNode(getTypeId(),
350                                     getContextManager());
351     }
352
353     /**
354      * Set the name in this ResultColumn. This is useful when you don't
355      * know the name at the time you create the ResultColumn, for example,
356      * in an insert-select statement, where you want the names of the
357      * result columns to match the table being inserted into, not the
358      * table they came from.
359      *
360      * @param name The name to set in this ResultColumn
361      */

362
363     public void setName(String JavaDoc name)
364     {
365         if (this.name == null)
366         {
367             this.name = name;
368         }
369         else {
370             if (SanityManager.DEBUG)
371             SanityManager.ASSERT(reference == null ||
372                 name.equals(reference.getColumnName()),
373                 "don't change name from reference name");
374         }
375
376         this.exposedName = name;
377     }
378
379     /**
380      * Is the name for this ResultColumn generated?
381      */

382     public boolean isNameGenerated()
383     {
384         return isNameGenerated;
385     }
386
387     /**
388      * Set that this result column name is generated.
389      */

390     public void setNameGenerated(boolean value)
391     {
392         isNameGenerated = value;
393     }
394
395     /**
396      * Set the resultSetNumber for this ResultColumn. This is the
397      * resultSetNumber for the ResultSet that we belong to. This
398      * is useful for generate() and necessary since we do not have a
399      * back pointer to the RSN.
400      *
401      * @param resultSetNumber The resultSetNumber.
402      */

403     public void setResultSetNumber(int resultSetNumber)
404     {
405         this.resultSetNumber = resultSetNumber;
406     }
407
408     /**
409      * Get the resultSetNumber for this ResultColumn.
410      *
411      * @return int The resultSetNumber.
412      */

413     public int getResultSetNumber()
414     {
415         return resultSetNumber;
416     }
417
418     /**
419      * Set the clause that this node appears in.
420      *
421      * @param clause The clause that this node appears in.
422      */

423     public void setClause(int clause)
424     {
425         super.setClause(clause);
426         /* expression will be null for AllResultColumn */
427         if (expression != null)
428         {
429             expression.setClause(clause);
430         }
431         else if (SanityManager.DEBUG)
432         {
433             SanityManager.ASSERT(this instanceof AllResultColumn,
434                 "this expected to be instanceof AllResultColumn when expression is null");
435         }
436     }
437
438     /**
439      * Adjust the virtualColumnId for this ResultColumn by the specified amount
440      *
441      * @param adjust The adjustment for the virtualColumnId
442      */

443
444     public void adjustVirtualColumnId(int adjust)
445     {
446         virtualColumnId += adjust;
447     }
448
449     /**
450      * Set the virtualColumnId for this ResultColumn
451      *
452      * @param id The virtualColumnId for this ResultColumn
453      */

454
455     public void setVirtualColumnId(int id)
456     {
457         virtualColumnId = id;
458     }
459
460     /**
461      * Get the virtualColumnId for this ResultColumn
462      *
463      * @return virtualColumnId for this ResultColumn
464      */

465     public int getVirtualColumnId()
466     {
467         return virtualColumnId;
468     }
469
470     /**
471      * Generate a unique (across the entire statement) column name for unnamed
472      * ResultColumns
473      *
474      * @exception StandardException Thrown on error
475      */

476     public void guaranteeColumnName() throws StandardException
477     {
478         if (exposedName == null)
479         {
480             /* Unions may also need generated names, if both sides name don't match */
481             exposedName ="SQLCol" + getCompilerContext().getNextColumnNumber();
482             isNameGenerated = true;
483         }
484     }
485
486     /**
487      * Convert this object to a String. See comments in QueryTreeNode.java
488      * for how this should be done for tree printing.
489      *
490      * @return This object as a String
491      */

492
493     public String JavaDoc toString()
494     {
495         if (SanityManager.DEBUG)
496         {
497             return "exposedName: " + exposedName + "\n" +
498                 "name: " + name + "\n" +
499                 "tableName: " + tableName + "\n" +
500                 "isNameGenerated: " + isNameGenerated + "\n" +
501                 "sourceTableName: " + sourceTableName + "\n" +
502                 "type: " + dataTypeServices + "\n" +
503                 "columnDescriptor: " + columnDescriptor + "\n" +
504                 "isGenerated: " + isGenerated + "\n" +
505                 "isGeneratedForUnmatchedColumnInInsert: " + isGeneratedForUnmatchedColumnInInsert + "\n" +
506                 "isGroupingColumn: " + isGroupingColumn + "\n" +
507                 "isReferenced: " + isReferenced + "\n" +
508                 "isRedundant: " + isRedundant + "\n" +
509                 "virtualColumnId: " + virtualColumnId + "\n" +
510                 "resultSetNumber: " + resultSetNumber + "\n" +
511                 super.toString();
512         }
513         else
514         {
515             return "";
516         }
517     }
518
519     /**
520      * Prints the sub-nodes of this object. See QueryTreeNode.java for
521      * how tree printing is supposed to work.
522      *
523      * @param depth The depth of this node in the tree
524      */

525
526     public void printSubNodes(int depth)
527     {
528         if (SanityManager.DEBUG)
529         {
530             super.printSubNodes(depth);
531             if (expression != null)
532             {
533                 printLabel(depth, "expression: ");
534                 expression.treePrint(depth + 1);
535             }
536             if (reference != null)
537             {
538                 printLabel(depth, "reference: ");
539                 reference.treePrint(depth + 1);
540             }
541         }
542     }
543
544     /**
545      * Bind this expression. This means binding the sub-expressions.
546      * In this case, we figure out what the result type of this result
547      * column is when we call one of the bindResultColumn*() methods.
548      * The reason is that there are different ways of binding the
549      * result columns depending on the statement type, and this is
550      * a standard interface that does not take the statement type as
551      * a parameter.
552      *
553      * @param fromList The FROM list for the query this
554      * expression is in, for binding columns.
555      * @param subqueryList The subquery list being built as we find SubqueryNodes
556      * @param aggregateVector The aggregate vector being built as we find AggregateNodes
557      *
558      * @return The new top of the expression tree.
559      *
560      * @exception StandardException Thrown on error
561      */

562
563     public ValueNode bindExpression(FromList fromList, SubqueryList subqueryList,
564                     Vector JavaDoc aggregateVector)
565                 throws StandardException
566     {
567         /*
568         ** Set the type of a parameter to the type of the result column.
569         ** Don't do it if this result column doesn't have a type yet.
570         ** This can happen if the parameter is part of a table constructor.
571         */

572         if (expression.requiresTypeFromContext())
573         {
574             if (getTypeServices() != null)
575             {
576                 expression.setType(getTypeServices());
577             }
578         }
579
580         expression = expression.bindExpression(fromList, subqueryList,
581                                     aggregateVector);
582
583         if (expression instanceof ColumnReference)
584         {
585             autoincrement = ((ColumnReference)expression).getSource().isAutoincrement();
586         }
587             
588
589         
590         return this;
591     }
592
593     /**
594      * Bind this result column by ordinal position and set the VirtualColumnId.
595      * This is useful for INSERT statements like "insert into t values (1, 2, 3)",
596      * where the user did not specify a column list.
597      * If a columnDescriptor is not found for a given position, then
598      * the user has specified more values than the # of columns in
599      * the table and an exception is thrown.
600      *
601      * NOTE: We must set the VirtualColumnId here because INSERT does not
602      * construct the ResultColumnList in the usual way.
603      *
604      * @param tableDescriptor The descriptor for the table being
605      * inserted into
606      * @param columnId The ordinal position of the column
607      * in the table, starting at 1.
608      *
609      * @exception StandardException Thrown on error
610      */

611
612     void bindResultColumnByPosition(TableDescriptor tableDescriptor,
613                     int columnId)
614                 throws StandardException
615     {
616         ColumnDescriptor columnDescriptor;
617
618         columnDescriptor = tableDescriptor.getColumnDescriptor(columnId);
619
620         if (columnDescriptor == null)
621         {
622             String JavaDoc errorString;
623             String JavaDoc schemaName;
624
625             errorString = "";
626             schemaName = tableDescriptor.getSchemaName();
627             if (schemaName != null)
628                 errorString += schemaName + ".";
629             errorString += tableDescriptor.getName();
630
631             throw StandardException.newException(SQLState.LANG_TOO_MANY_RESULT_COLUMNS, errorString);
632         }
633
634         setColumnDescriptor(tableDescriptor, columnDescriptor);
635         setVirtualColumnId(columnId);
636     }
637
638     /**
639      * Bind this result column by its name and set the VirtualColumnId.
640      * This is useful for update statements, and for INSERT statements
641      * like "insert into t (a, b, c) values (1, 2, 3)" where the user
642      * specified a column list.
643      * An exception is thrown when a columnDescriptor cannot be found for a
644      * given name. (There is no column with that name.)
645      *
646      * NOTE: We must set the VirtualColumnId here because INSERT does not
647      * construct the ResultColumnList in the usual way.
648      *
649      * @param tableDescriptor The descriptor for the table being
650      * updated or inserted into
651      * @param columnId The ordinal position of the column
652      * in the table, starting at 1. (Used to
653      * set the VirtualColumnId.)
654      *
655      * @exception StandardException Thrown on error
656      */

657
658     public void bindResultColumnByName(TableDescriptor tableDescriptor,
659                     int columnId)
660                 throws StandardException
661     {
662         ColumnDescriptor columnDescriptor;
663
664         columnDescriptor = tableDescriptor.getColumnDescriptor(exposedName);
665
666         if (columnDescriptor == null)
667         {
668             String JavaDoc errorString;
669             String JavaDoc schemaName;
670
671             errorString = "";
672             schemaName = tableDescriptor.getSchemaName();
673             if (schemaName != null)
674                 errorString += schemaName + ".";
675             errorString += tableDescriptor.getName();
676
677             throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, exposedName, errorString);
678         }
679
680         setColumnDescriptor(tableDescriptor, columnDescriptor);
681         setVirtualColumnId(columnId);
682         if (isPrivilegeCollectionRequired())
683             getCompilerContext().addRequiredColumnPriv( columnDescriptor);
684     }
685     
686     /**
687      * Change an untyped null to a typed null.
688      *
689      * @exception StandardException Thrown on error
690      */

691     public void typeUntypedNullExpression( ResultColumn bindingRC)
692             throws StandardException
693     {
694         TypeId typeId = bindingRC.getTypeId();
695         /* This is where we catch null in a VALUES clause outside
696          * of INSERT VALUES()
697          */

698         if (typeId == null)
699         {
700             throw StandardException.newException(SQLState.LANG_NULL_IN_VALUES_CLAUSE);
701         }
702
703         if( expression instanceof UntypedNullConstantNode)
704             expression = getNullNode( typeId, getContextManager());
705         else if( ( expression instanceof ColumnReference) && expression.getTypeServices() == null)
706         {
707             // The expression must be a reference to a null column in a values table.
708
expression.setType( bindingRC.getType());
709         }
710     }
711
712     /**
713      * Set the column descriptor for this result column. It also gets
714      * the data type services from the column descriptor and stores it in
715      * this result column: this is redundant, but we have to store the result
716      * type here for SELECT statements, and it is more orthogonal if the type
717      * can be found here regardless of what type of statement it is.
718      *
719      * @param tableDescriptor The TableDescriptor for the table
720      * being updated or inserted into.
721      * This parameter is used only for
722      * error reporting.
723      * @param columnDescriptor The ColumnDescriptor to set in
724      * this ResultColumn.
725      *
726      * @exception StandardException tableNameMismatch
727      */

728     void setColumnDescriptor(TableDescriptor tableDescriptor,
729                 ColumnDescriptor columnDescriptor) throws StandardException
730     {
731         /* Callers are responsible for verifying that the column exists */
732         if (SanityManager.DEBUG)
733         SanityManager.ASSERT(columnDescriptor != null,
734                     "Caller is responsible for verifying that column exists");
735
736         setType(columnDescriptor.getType());
737         this.columnDescriptor = columnDescriptor;
738
739         /*
740             If the node was created using a reference, the table name
741             of the reference must agree with that of the tabledescriptor.
742          */

743         if (reference != null && reference.getTableName() != null)
744         {
745             if (! tableDescriptor.getName().equals(
746                     reference.getTableName()) )
747             {
748                 /* REMIND: need to have schema name comparison someday as well...
749                 ** left out for now, lots of null checking needed...
750                 ** || ! tableDescriptor.getSchemaName().equals(
751                 ** reference.getTableNameNode().getSchemaName())) {
752                 */

753                 String JavaDoc realName = tableDescriptor.getName();
754                 String JavaDoc refName = reference.getTableName();
755
756                 throw StandardException.newException(SQLState.LANG_TABLE_NAME_MISMATCH,
757                     realName, refName);
758             }
759         }
760     }
761
762     /**
763      * Bind the result column to the expression that lives under it.
764      * All this does is copy the datatype information to this node.
765      * This is useful for SELECT statements, where the result type
766      * of each column is the type of the column's expression.
767      *
768      * @exception StandardException Thrown on error
769      */

770     public void bindResultColumnToExpression()
771                 throws StandardException
772     {
773         /*
774         ** This gets the same DataTypeServices object as
775         ** is used in the expression. It is probably not
776         ** necessary to clone the object here.
777         */

778         setType(expression.getTypeServices());
779
780         if (expression instanceof ColumnReference)
781         {
782             ColumnReference cr = (ColumnReference) expression;
783             tableName = cr.getTableName();
784             sourceTableName = cr.getSourceTableName();
785             sourceSchemaName = cr.getSourceSchemaName();
786         }
787     }
788
789     /**
790      * Preprocess an expression tree. We do a number of transformations
791      * here (including subqueries, IN lists, LIKE and BETWEEN) plus
792      * subquery flattening.
793      * NOTE: This is done before the outer ResultSetNode is preprocessed.
794      *
795      * @param numTables Number of tables in the DML Statement
796      * @param outerFromList FromList from outer query block
797      * @param outerSubqueryList SubqueryList from outer query block
798      * @param outerPredicateList PredicateList from outer query block
799      *
800      * @return The modified expression
801      *
802      * @exception StandardException Thrown on error
803      */

804     public ValueNode preprocess(int numTables,
805                                 FromList outerFromList,
806                                 SubqueryList outerSubqueryList,
807                                 PredicateList outerPredicateList)
808                     throws StandardException
809     {
810         if (expression == null)
811             return this;
812         expression = expression.preprocess(numTables, outerFromList,
813                                            outerSubqueryList,
814                                            outerPredicateList);
815         return this;
816     }
817
818     /**
819         This verifies that the expression is storable into the result column.
820         It checks versus the given ResultColumn.
821
822         This method should not be called until the result column and
823         expression both have a valid type, i.e. after they are bound
824         appropriately. Its use is for statements like insert, that need to
825         verify if a given value can be stored into a column.
826
827         @exception StandardException thrown if types not suitable.
828      */

829     public void checkStorableExpression(ResultColumn toStore)
830                     throws StandardException
831     {
832         TypeId columnTypeId, toStoreTypeId;
833
834         toStoreTypeId = toStore.getTypeId();
835         if( toStoreTypeId == null)
836             return;
837         
838         columnTypeId = getTypeId();
839
840         if (! getTypeCompiler().storable(toStoreTypeId, getClassFactory()))
841             throw StandardException.newException(SQLState.LANG_NOT_STORABLE,
842                 columnTypeId.getSQLTypeName(),
843                 toStoreTypeId.getSQLTypeName() );
844     }
845
846     /**
847         This verifies that the expression is storable into the result column.
848         It checks versus the expression under this ResultColumn.
849
850         This method should not be called until the result column and
851         expression both have a valid type, i.e. after they are bound
852         appropriately. Its use is for statements like update, that need to
853         verify if a given value can be stored into a column.
854
855         @exception StandardException thrown if types not suitable.
856      */

857     public void checkStorableExpression()
858                     throws StandardException
859     {
860         TypeId columnTypeId = getTypeId();
861         TypeId toStoreTypeId = getExpressionType().getTypeId();
862
863         if (! getTypeCompiler().storable(toStoreTypeId, getClassFactory()))
864             throw StandardException.newException(SQLState.LANG_NOT_STORABLE,
865                 columnTypeId.getSQLTypeName(),
866                 toStoreTypeId.getSQLTypeName() );
867     }
868
869     /**
870      * Do code generation for a result column. This consists of doing the code
871      * generation for the underlying expression.
872      *
873      * @param ecb The ExpressionClassBuilder for the class we're generating
874      * @param mb The method the expression will go into
875      *
876      *
877      * @exception StandardException Thrown on error
878      */

879
880     public void generateExpression(ExpressionClassBuilder ecb,
881                                             MethodBuilder mb)
882                                     throws StandardException
883     {
884         expression.generateExpression(ecb, mb);
885     }
886
887     /**
888      * Do code generation to return a Null of the appropriate type
889      * for the result column.
890        Requires the getCOlumnExpress value pushed onto the stack
891      *
892      * @param acb The ActivationClassBuilder for the class we're generating
893      * @param eb The ExpressionBlock that the generate code is to go into
894      * @param getColumnExpression "fieldx.getColumn(y)"
895      *
896      * @exception StandardException Thrown on error
897      */

898 /*PUSHCOMPILE
899     public void generateNulls(ExpressionClassBuilder acb,
900                                     MethodBuilder mb,
901                                     Expression getColumnExpress)
902             throws StandardException
903     {
904
905         acb.pushDataValueFactory(mb);
906         getTypeCompiler().generateNull(mb, acb.getBaseClassName());
907
908         
909         mb.cast(ClassName.DataValueDescriptor);
910
911
912         return eb.newCastExpression(
913                     ClassName.DataValueDescriptor,
914                     getTypeCompiler().
915                         generateNull(
916                                     eb,
917                                     acb.getBaseClassName(),
918                                     acb.getDataValueFactory(eb),
919                                     getColumnExpress));
920     }
921 */

922     /**
923         Generate the code to create a column the same shape and
924         size as this ResultColumn.
925
926         Used in ResultColumnList.generateHolder().
927
928         @exception StandardException thrown on failure
929     */

930     public void generateHolder(ExpressionClassBuilder acb,
931                                     MethodBuilder mb)
932         throws StandardException
933     {
934         // generate expression of the form
935
// (DataValueDescriptor) columnSpace
936

937         acb.generateNull(mb, getTypeCompiler());
938         mb.upCast(ClassName.DataValueDescriptor);
939     }
940
941     /*
942     ** Check whether the column length and type of this result column
943     ** match the expression under the columns. This is useful for
944     ** INSERT and UPDATE statements. For SELECT statements this method
945     ** should always return true. There is no need to call this for a
946     ** DELETE statement.
947     **
948     ** @return true means the column matches its expressions,
949     ** false means it doesn't match.
950     */

951
952     boolean columnTypeAndLengthMatch()
953         throws StandardException
954     {
955         DataTypeDescriptor resultColumnType;
956         DataTypeDescriptor expressionType = expression.getTypeServices();
957
958         /*
959         ** We can never make any assumptions about
960         ** parameters. So don't even bother in this
961         ** case.
962         */

963         if (expression.requiresTypeFromContext())
964         {
965             return false;
966         }
967
968         resultColumnType = getType();
969
970         if (SanityManager.DEBUG)
971         {
972             if (! (resultColumnType != null))
973             {
974                 SanityManager.THROWASSERT("Type is null for column " +
975                                           this);
976             }
977         }
978
979         // Are we inserting/updating an XML column? If so, we always
980
// return false so that normalization will occur. We have to
981
// do this because there are different "kinds" of XML values
982
// and we need to make sure they match--but we don't know
983
// the "kind" until execution time. See the "normalize"
984
// method in org.apache.derby.iapi.types.XML for more.
985
if (resultColumnType.getTypeId().isXMLTypeId())
986             return false;
987
988         /* Are they the same type? */
989         if ( ! resultColumnType.getTypeId().getSQLTypeName().equals(
990             expressionType.getTypeId().getSQLTypeName()
991                 )
992             )
993         {
994             return false;
995         }
996
997         /* Are they the same precision? */
998         if (resultColumnType.getPrecision() != expressionType.getPrecision())
999         {
1000            return false;
1001        }
1002
1003        /* Are they the same scale? */
1004        if (resultColumnType.getScale() != expressionType.getScale())
1005        {
1006            return false;
1007        }
1008
1009        /* Are they the same width? */
1010        if (resultColumnType.getMaximumWidth() != expressionType.getMaximumWidth())
1011        {
1012            return false;
1013        }
1014
1015        /* Is the source nullable and the target non-nullable? */
1016        if ((! resultColumnType.isNullable()) && expressionType.isNullable())
1017        {
1018            return false;
1019        }
1020
1021        return true;
1022    }
1023
1024    boolean columnTypeAndLengthMatch(ResultColumn otherColumn)
1025        throws StandardException
1026    {
1027        DataTypeDescriptor resultColumnType;
1028        DataTypeDescriptor otherResultColumnType;
1029        ValueNode otherExpression = otherColumn.getExpression();
1030
1031        resultColumnType = getType();
1032        otherResultColumnType = otherColumn.getType();
1033
1034        if (SanityManager.DEBUG)
1035        {
1036            SanityManager.ASSERT(resultColumnType != null,
1037                    "Type is null for column " + this);
1038            SanityManager.ASSERT(otherResultColumnType != null,
1039                    "Type is null for column " + otherColumn);
1040        }
1041
1042        /*
1043        ** We can never make any assumptions about
1044        ** parameters. So don't even bother in this
1045        ** case.
1046        */

1047        if ((otherExpression != null) && (otherExpression.requiresTypeFromContext()) ||
1048            (expression.requiresTypeFromContext()))
1049        {
1050            return false;
1051        }
1052
1053        // Are we inserting/updating an XML column? If so, we always
1054
// return false so that normalization will occur. We have to
1055
// do this because there are different "kinds" of XML values
1056
// and we need to make sure they match--but we don't know
1057
// the "kind" until execution time. See the "normalize"
1058
// method in org.apache.derby.iapi.types.XML for more.
1059
if (resultColumnType.getTypeId().isXMLTypeId())
1060            return false;
1061
1062        /* Are they the same type? */
1063        if ( ! resultColumnType.getTypeId().equals(
1064            otherResultColumnType.getTypeId()
1065                )
1066            )
1067        {
1068            /* If the source is a constant of a different type then
1069             * we try to convert that constant to a constant of our
1070             * type. (The initial implementation only does the conversion
1071             * to string types because the most common problem is a char
1072             * constant with a varchar column.)
1073             * NOTE: We do not attempt any conversion here if the source
1074             * is a string type and the target is not or vice versa in
1075             * order to avoid problems with implicit varchar conversions.
1076             * Anyway, we will check if the "converted" constant has the
1077             * same type as the original constant. If not, then the conversion
1078             * happened. In that case, we will reuse the ConstantNode, for simplicity,
1079             * and reset the type to match the desired type.
1080             */

1081            if (otherExpression instanceof ConstantNode)
1082            {
1083                ConstantNode constant = (ConstantNode)otherColumn.getExpression();
1084                DataValueDescriptor oldValue = constant.getValue();
1085
1086
1087                DataValueDescriptor newValue = convertConstant(
1088                    resultColumnType.getTypeId(),
1089                    resultColumnType.getMaximumWidth(), oldValue);
1090
1091                if ((oldValue != newValue) &&
1092                    (oldValue instanceof StringDataValue ==
1093                     newValue instanceof StringDataValue))
1094                {
1095                    constant.setValue(newValue);
1096                    constant.setType(getTypeServices());
1097                    otherColumn.bindResultColumnToExpression();
1098                    otherResultColumnType = otherColumn.getType();
1099                }
1100            }
1101            if ( ! resultColumnType.getTypeId().equals(
1102                otherResultColumnType.getTypeId()
1103                    )
1104                )
1105            {
1106                return false;
1107            }
1108        }
1109
1110        /* Are they the same precision? */
1111        if (resultColumnType.getPrecision() !=
1112                                        otherResultColumnType.getPrecision())
1113        {
1114            return false;
1115        }
1116
1117        /* Are they the same scale? */
1118        if (resultColumnType.getScale() != otherResultColumnType.getScale())
1119        {
1120            return false;
1121        }
1122
1123        /* Are they the same width? */
1124        if (resultColumnType.getMaximumWidth() !=
1125                                        otherResultColumnType.getMaximumWidth())
1126        {
1127            return false;
1128        }
1129
1130        /* Is the source nullable and the target non-nullable?
1131         * The source is nullable if it is nullable or if the target is generated
1132         * for an unmatched column in an insert with a column list.
1133         * This additional check is needed because when we generate any additional
1134         * source RCs for an insert with a column list the generated RCs for any
1135         * non-specified columns get the type info from the column. Thus,
1136         * for t1(non_nullable, nullable)
1137         * insert into t2 (nullable) values 1;
1138         * RCType.isNullable() returns false for the generated source RC for
1139         * non_nullable. In this case, we want to see it as
1140         */

1141        if ((! resultColumnType.isNullable()) &&
1142                    (otherResultColumnType.isNullable() ||
1143                     otherColumn.isGeneratedForUnmatchedColumnInInsert()))
1144        {
1145            return false;
1146        }
1147
1148        return true;
1149    }
1150
1151    /**
1152     * Is this a generated column?
1153     *
1154     * @return Boolean - whether or not this column is a generated column.
1155     */

1156    public boolean isGenerated()
1157    {
1158        return (isGenerated == true);
1159    }
1160
1161    /**
1162     * Is this columm generated for an unmatched column in an insert?
1163     *
1164     * @return Boolean - whether or not this columm was generated for an unmatched column in an insert.
1165     */

1166    public boolean isGeneratedForUnmatchedColumnInInsert()
1167    {
1168        return (isGeneratedForUnmatchedColumnInInsert == true);
1169    }
1170
1171    /**
1172     * Mark this a columm as a generated column
1173     */

1174    public void markGenerated()
1175    {
1176        isGenerated = true;
1177        /* A generated column is a referenced column */
1178        isReferenced = true;
1179    }
1180
1181    /**
1182     * Mark this a columm as generated for an unmatched column in an insert
1183     */

1184    public void markGeneratedForUnmatchedColumnInInsert()
1185    {
1186        isGeneratedForUnmatchedColumnInInsert = true;
1187        /* A generated column is a referenced column */
1188        isReferenced = true;
1189    }
1190
1191    /**
1192     * Is this a referenced column?
1193     *
1194     * @return Boolean - whether or not this column is a referenced column.
1195     */

1196    public boolean isReferenced()
1197    {
1198        return isReferenced;
1199    }
1200
1201    /**
1202     * Mark this column as a referenced column.
1203     */

1204    public void setReferenced()
1205    {
1206        isReferenced = true;
1207    }
1208
1209    /**
1210     * Mark this column as a referenced column if it is already marked as referenced or if any result column in
1211     * its chain of virtual columns is marked as referenced.
1212     */

1213    void pullVirtualIsReferenced()
1214    {
1215        if( isReferenced())
1216            return;
1217        
1218        for( ValueNode expr = expression; expr != null && (expr instanceof VirtualColumnNode);)
1219        {
1220            VirtualColumnNode vcn = (VirtualColumnNode) expr;
1221            ResultColumn src = vcn.getSourceColumn();
1222            if( src.isReferenced())
1223            {
1224                setReferenced();
1225                return;
1226            }
1227            expr = src.getExpression();
1228        }
1229    } // end of pullVirtualIsReferenced
1230

1231    /**
1232     * Mark this column as an unreferenced column.
1233     */

1234    public void setUnreferenced()
1235    {
1236        isReferenced = false;
1237    }
1238
1239    /**
1240     * Mark this RC and all RCs in the underlying
1241     * RC/VCN chain as referenced.
1242     */

1243    void markAllRCsInChainReferenced()
1244    {
1245        setReferenced();
1246
1247        ValueNode vn = expression;
1248
1249        while (vn instanceof VirtualColumnNode)
1250        {
1251            VirtualColumnNode vcn = (VirtualColumnNode) vn;
1252            ResultColumn rc = vcn.getSourceColumn();
1253            rc.setReferenced();
1254            vn = rc.getExpression();
1255        }
1256    }
1257
1258    /**
1259     * Is this a redundant ResultColumn?
1260     *
1261     * @return Boolean - whether or not this RC is redundant.
1262     */

1263    public boolean isRedundant()
1264    {
1265        return isRedundant;
1266    }
1267
1268    /**
1269     * Mark this ResultColumn as redundant.
1270     */

1271    public void setRedundant()
1272    {
1273        isRedundant = true;
1274    }
1275
1276    /**
1277     * Mark this ResultColumn as a grouping column in the SELECT list
1278     */

1279    public void markAsGroupingColumn()
1280    {
1281        isGroupingColumn = true;
1282    }
1283
1284    /**
1285     * Look for and reject ?/-?/+? parameter under this ResultColumn. This is
1286     * called for SELECT statements.
1287     *
1288     * @exception StandardException Thrown if a ?/-?/+? parameter was found
1289     * directly under this ResultColumn.
1290     */

1291
1292    void rejectParameter() throws StandardException
1293    {
1294        if ((expression != null) && (expression.isParameterNode()))
1295            throw StandardException.newException(SQLState.LANG_PARAM_IN_SELECT_LIST);
1296        if ((expression != null) && (expression instanceof UnaryOperatorNode) &&
1297                ((UnaryOperatorNode)expression).isUnaryMinusOrPlusWithParameter())
1298            throw StandardException.newException(SQLState.LANG_PARAM_IN_SELECT_LIST);
1299    }
1300
1301    /*
1302    ** The following methods implement the Comparable interface.
1303    */

1304    public int compareTo(Object JavaDoc other)
1305    {
1306        ResultColumn otherResultColumn = (ResultColumn) other;
1307
1308        return this.getColumnPosition() - otherResultColumn.getColumnPosition();
1309    }
1310
1311    /**
1312     * Mark this column as being updated by an update statemment.
1313     */

1314    void markUpdated()
1315    {
1316        updated = true;
1317    }
1318
1319    /**
1320     * Mark this column as being updatable, so we can make sure it is in the
1321     * "for update" list of a positioned update.
1322     */

1323    void markUpdatableByCursor()
1324    {
1325        updatableByCursor = true;
1326    }
1327
1328    /**
1329     * Tell whether this column is being updated.
1330     *
1331     * @return true means this column is being updated.
1332     */

1333    boolean updated()
1334    {
1335        return updated;
1336    }
1337
1338    /**
1339     * Tell whether this column is updatable by a positioned update.
1340     *
1341     * @return true means this column is updatable
1342     */

1343    public boolean updatableByCursor()
1344    {
1345        return updatableByCursor;
1346    }
1347
1348    /**
1349     * @see QueryTreeNode#disablePrivilegeCollection
1350     */

1351    public void disablePrivilegeCollection()
1352    {
1353        super.disablePrivilegeCollection();
1354        if (expression != null)
1355            expression.disablePrivilegeCollection();
1356    }
1357
1358    /**
1359     * Make a copy of this ResultColumn in a new ResultColumn
1360     *
1361     * @return A new ResultColumn with the same contents as this one
1362     *
1363     * @exception StandardException Thrown on error
1364     */

1365    ResultColumn cloneMe() throws StandardException
1366    {
1367        ResultColumn newResultColumn;
1368        ValueNode cloneExpr;
1369
1370        /* If expression is a ColumnReference, then we want to
1371         * have the RC's clone have a clone of the ColumnReference
1372         * for it's expression. This is for the special case of
1373         * cloning the SELECT list for the HAVING clause in the parser.
1374         * The SELECT generated for the HAVING needs its own copy
1375         * of the ColumnReferences.
1376         */

1377        if (expression instanceof ColumnReference)
1378        {
1379            cloneExpr = ((ColumnReference) expression).getClone();
1380        }
1381        else
1382        {
1383            cloneExpr = expression;
1384        }
1385
1386        /* If a columnDescriptor exists, then we must propagate it */
1387        if (columnDescriptor != null)
1388        {
1389            newResultColumn = (ResultColumn) getNodeFactory().getNode(
1390                                                    C_NodeTypes.RESULT_COLUMN,
1391                                                    columnDescriptor,
1392                                                    expression,
1393                                                    getContextManager());
1394            newResultColumn.setExpression(cloneExpr);
1395        }
1396        else
1397        {
1398
1399            newResultColumn = (ResultColumn) getNodeFactory().getNode(
1400                                                    C_NodeTypes.RESULT_COLUMN,
1401                                                    getName(),
1402                                                    cloneExpr,
1403                                                    getContextManager());
1404        }
1405
1406        /* Set the VirtualColumnId and name in the new node */
1407        newResultColumn.setVirtualColumnId(getVirtualColumnId());
1408
1409        /* Set the type and name information in the new node */
1410        newResultColumn.setName(getName());
1411        newResultColumn.setType(getTypeServices());
1412        newResultColumn.setNameGenerated(isNameGenerated());
1413
1414        /* Set the "is generated for unmatched column in insert" status in the new node
1415        This if for bug 4194*/

1416        if (isGeneratedForUnmatchedColumnInInsert())
1417            newResultColumn.markGeneratedForUnmatchedColumnInInsert();
1418
1419        /* Set the "is referenced" status in the new node */
1420        if (isReferenced())
1421            newResultColumn.setReferenced();
1422
1423        /* Set the "updated" status in the new node */
1424        if (updated())
1425            newResultColumn.markUpdated();
1426
1427        /* Setthe "updatable by cursor" status in the new node */
1428        if (updatableByCursor())
1429            newResultColumn.markUpdatableByCursor();
1430
1431        if (isAutoincrementGenerated())
1432            newResultColumn.setAutoincrementGenerated();
1433
1434        if (isAutoincrement())
1435            newResultColumn.setAutoincrement();
1436        if (isGroupingColumn())
1437            newResultColumn.markAsGroupingColumn();
1438        return newResultColumn;
1439    }
1440
1441    /**
1442     * Get the maximum size of the column
1443     *
1444     * @return the max size
1445     */

1446    public int getMaximumColumnSize()
1447    {
1448        return dataTypeServices.getTypeId()
1449            .getApproximateLengthInBytes(dataTypeServices);
1450    }
1451
1452    /**
1453     * Return the variant type for the underlying expression.
1454     * The variant type can be:
1455     * VARIANT - variant within a scan
1456     * (method calls and non-static field access)
1457     * SCAN_INVARIANT - invariant within a scan
1458     * (column references from outer tables)
1459     * QUERY_INVARIANT - invariant within the life of a query
1460     * CONSTANT - constant
1461     *
1462     * @return The variant type for the underlying expression.
1463     * @exception StandardException thrown on error
1464     */

1465    protected int getOrderableVariantType() throws StandardException
1466    {
1467        /*
1468        ** If the expression is VARIANT, then
1469        ** return VARIANT. Otherwise, we return
1470        ** CONSTANT. For result columns that are
1471        ** generating autoincrement values, the result
1472        ** is variant-- note that there is no expression
1473        ** associated with an autoincrement column in
1474        ** an insert statement.
1475        */

1476        int expType = ((expression != null) ?
1477                       expression.getOrderableVariantType() :
1478                       ((isAutoincrementGenerated()) ?
1479                        Qualifier.VARIANT : Qualifier.CONSTANT));
1480
1481        switch (expType)
1482        {
1483            case Qualifier.VARIANT:
1484                    return Qualifier.VARIANT;
1485
1486            case Qualifier.SCAN_INVARIANT:
1487            case Qualifier.QUERY_INVARIANT:
1488                    return Qualifier.SCAN_INVARIANT;
1489
1490            default:
1491                    return Qualifier.CONSTANT;
1492        }
1493    }
1494
1495    /**
1496     * Accept a visitor, and call v.visit()
1497     * on child nodes as necessary.
1498     *
1499     * @param v the visitor
1500     *
1501     * @exception StandardException on error
1502     */

1503    public Visitable accept(Visitor v)
1504        throws StandardException
1505    {
1506        Visitable returnNode = v.visit(this);
1507
1508        if (v.skipChildren(this))
1509        {
1510            return returnNode;
1511        }
1512    
1513        if (expression != null && !v.stopTraversal())
1514        {
1515            expression = (ValueNode)expression.accept(v);
1516        }
1517        return returnNode;
1518    }
1519
1520    /**
1521     * Set the nullability of this ResultColumn.
1522     */

1523    public void setNullability(boolean nullability)
1524    {
1525        dataTypeServices.setNullability(nullability);
1526    }
1527
1528    /**
1529     * Is this column in this array of strings?
1530     *
1531     * @param list the array of column names to compare
1532     *
1533     * @return true/false
1534     */

1535    public boolean foundInList(String JavaDoc[] list)
1536    {
1537        return foundString(list, name);
1538    }
1539
1540    /**
1541     * Verify that this RC is orderable.
1542     *
1543     * @exception StandardException Thrown on error
1544     */

1545    void verifyOrderable() throws StandardException
1546    {
1547        /*
1548         * Do not check to see if we can map user types
1549         * to built-in types. The ability to do so does
1550         * not mean that ordering will work. In fact,
1551         * as of version 2.0, ordering does not work on
1552         * user types.
1553         */

1554        if (!getTypeId().orderable(getClassFactory()))
1555        {
1556            throw StandardException.newException(SQLState.LANG_COLUMN_NOT_ORDERABLE_DURING_EXECUTION,
1557                        getTypeId().getSQLTypeName());
1558        }
1559    }
1560
1561    /**
1562      If this ResultColumn is bound to a column in a table
1563      get the column descriptor for the column in the table.
1564      Otherwise return null.
1565      */

1566    ColumnDescriptor getTableColumnDescriptor() {return columnDescriptor;}
1567
1568    /**
1569     * Returns true if this result column is a placeholder for a generated
1570     * autoincrement value.
1571     */

1572    public boolean isAutoincrementGenerated()
1573    {
1574        return autoincrementGenerated;
1575    }
1576
1577    public void setAutoincrementGenerated()
1578    {
1579        autoincrementGenerated = true;
1580    }
1581
1582    public void resetAutoincrementGenerated()
1583    {
1584        autoincrementGenerated = false;
1585    }
1586
1587    public boolean isAutoincrement()
1588    {
1589        return autoincrement;
1590    }
1591
1592    public void setAutoincrement()
1593    {
1594        autoincrement = true;
1595    }
1596        
1597        public boolean isGroupingColumn()
1598        {
1599            return isGroupingColumn;
1600        }
1601        
1602    /**
1603     * @exception StandardException Thrown on error
1604     */

1605    private DataValueDescriptor convertConstant(TypeId toTypeId, int maxWidth, DataValueDescriptor constantValue)
1606        throws StandardException
1607    {
1608        int formatId = toTypeId.getTypeFormatId();
1609        DataValueFactory dvf = getDataValueFactory();
1610        switch (formatId)
1611        {
1612            default:
1613            case StoredFormatIds.CHAR_TYPE_ID:
1614                return constantValue;
1615
1616            case StoredFormatIds.VARCHAR_TYPE_ID:
1617            case StoredFormatIds.NATIONAL_CHAR_TYPE_ID:
1618            case StoredFormatIds.NATIONAL_VARCHAR_TYPE_ID:
1619                String JavaDoc sourceValue = constantValue.getString();
1620                int sourceWidth = sourceValue.length();
1621                int posn;
1622
1623                /*
1624                ** If the input is already the right length, no normalization is
1625                ** necessary - just return the source.
1626                **
1627                */

1628
1629                if (sourceWidth <= maxWidth)
1630                {
1631                    switch (formatId)
1632                    {
1633                        // For NCHAR we must pad the result, saves on normilization later if all
1634
// constants are of the correct size
1635
case StoredFormatIds.NATIONAL_CHAR_TYPE_ID:
1636
1637                            if (sourceWidth < maxWidth)
1638                            {
1639                                StringBuffer JavaDoc stringBuffer = new StringBuffer JavaDoc(sourceValue);
1640
1641                                int needed = maxWidth - sourceWidth;
1642                                char blankArray[] = new char[needed];
1643                                for (int i = 0; i < needed; i++)
1644                                    blankArray[i] = ' ';
1645                                stringBuffer.append(blankArray, 0,
1646                                                maxWidth - sourceWidth);
1647                                sourceValue = stringBuffer.toString();
1648                            }
1649                            return dvf.getNationalCharDataValue(sourceValue);
1650
1651                        case StoredFormatIds.NATIONAL_VARCHAR_TYPE_ID:
1652                            return dvf.getNationalVarcharDataValue(sourceValue);
1653
1654                        case StoredFormatIds.VARCHAR_TYPE_ID:
1655                            return dvf.getVarcharDataValue(sourceValue);
1656                    }
1657                }
1658
1659                /*
1660                ** Check whether any non-blank characters will be truncated.
1661                */

1662                for (posn = maxWidth; posn < sourceWidth; posn++)
1663                {
1664                    if (sourceValue.charAt(posn) != ' ')
1665                    {
1666                        String JavaDoc typeName = null;
1667                        switch (formatId)
1668                        {
1669                            case StoredFormatIds.NATIONAL_CHAR_TYPE_ID:
1670                                typeName = TypeId.NATIONAL_CHAR_NAME;
1671                                break;
1672
1673                            case StoredFormatIds.NATIONAL_VARCHAR_TYPE_ID:
1674                                typeName = TypeId.NATIONAL_VARCHAR_NAME;
1675                                break;
1676
1677                            case StoredFormatIds.VARCHAR_TYPE_ID:
1678                                typeName = TypeId.VARCHAR_NAME;
1679                                break;
1680                        }
1681                        throw StandardException.newException(SQLState.LANG_STRING_TRUNCATION,
1682                                                     typeName,
1683                                                     StringUtil.formatForPrint(sourceValue),
1684                                                     String.valueOf(maxWidth));
1685                    }
1686                }
1687
1688                switch (formatId)
1689                {
1690                    case StoredFormatIds.NATIONAL_CHAR_TYPE_ID:
1691                        return dvf.getNationalCharDataValue(sourceValue.substring(0, maxWidth));
1692
1693                    case StoredFormatIds.NATIONAL_VARCHAR_TYPE_ID:
1694                        return dvf.getNationalVarcharDataValue(sourceValue.substring(0, maxWidth));
1695
1696                    case StoredFormatIds.VARCHAR_TYPE_ID:
1697                        return dvf.getVarcharDataValue(sourceValue.substring(0, maxWidth));
1698                }
1699
1700            case StoredFormatIds.LONGVARCHAR_TYPE_ID:
1701                //No need to check widths here (unlike varchar), since no max width
1702
return dvf.getLongvarcharDataValue(constantValue.getString());
1703
1704            case StoredFormatIds.NATIONAL_LONGVARCHAR_TYPE_ID:
1705                //No need to check widths here (unlike varchar), since no max width
1706
return dvf.getNationalLongvarcharDataValue(constantValue.getString());
1707
1708        }
1709    }
1710
1711    /**
1712     * Get the TypeId from this Node.
1713     *
1714     * @return The TypeId from this Node. This
1715     * may be null if the node isn't bound yet.
1716     */

1717    public TypeId getTypeId() throws StandardException
1718    {
1719        TypeId t = super.getTypeId();
1720        if( t == null)
1721        {
1722            if( expression != null)
1723            {
1724                DataTypeDescriptor dtd = getTypeServices();
1725                if( dtd != null)
1726                    t = dtd.getTypeId();
1727            }
1728        }
1729        return t;
1730    } // end of getTypeId
1731

1732    /**
1733     * Get the DataTypeServices from this Node.
1734     *
1735     * @return The DataTypeServices from this Node. This
1736     * may be null if the node isn't bound yet.
1737     */

1738    public DataTypeDescriptor getTypeServices() throws StandardException
1739    {
1740        DataTypeDescriptor dtd = super.getTypeServices();
1741        if( dtd == null && expression != null)
1742        {
1743            dtd = expression.getTypeServices();
1744            if( dtd != null)
1745                setType( dtd);
1746        }
1747        return dtd;
1748    } // end of getTypeServices
1749

1750    public TableName getTableNameObject() {
1751        return null;
1752    }
1753
1754    /* Get the wrapped reference if any */
1755    public ColumnReference getReference() { return reference; }
1756    
1757    /**
1758     * Get the source BaseColumnNode for this result column. The
1759     * BaseColumnNode cannot be found unless the ResultColumn is bound
1760     * and is a simple reference to a column in a BaseFromTable.
1761     *
1762     * @return a BaseColumnNode,
1763     * or null if a BaseColumnNode cannot be found
1764     */

1765    public BaseColumnNode getBaseColumnNode() {
1766        ValueNode vn = expression;
1767        while (true) {
1768            if (vn instanceof ResultColumn) {
1769                vn = ((ResultColumn) vn).expression;
1770            } else if (vn instanceof ColumnReference) {
1771                vn = ((ColumnReference) vn).getSource();
1772            } else if (vn instanceof VirtualColumnNode) {
1773                vn = ((VirtualColumnNode) vn).getSourceColumn();
1774            } else if (vn instanceof BaseColumnNode) {
1775                return (BaseColumnNode) vn;
1776            } else {
1777                return null;
1778            }
1779        }
1780    }
1781
1782    /**
1783     * Search the tree beneath this ResultColumn until we find
1784     * the number of the table to which this RC points, and
1785     * return that table number. If we can't determine which
1786     * table this RC is for, then return -1.
1787     *
1788     * There are two places we can find the table number: 1) if
1789     * our expression is a ColumnReference, then we can get the
1790     * target table number from the ColumnReference and that's
1791     * it; 2) if expression is a VirtualColumnNode, then if
1792     * the VirtualColumnNode points to a FromBaseTable, we can
1793     * get that FBT's table number; otherwise, we walk the
1794     * VirtualColumnNode-ResultColumn chain and do a recursive
1795     * search.
1796     *
1797     * @return The number of the table to which this ResultColumn
1798     * points, or -1 if we can't determine that from where we are.
1799     */

1800    public int getTableNumber()
1801        throws StandardException
1802    {
1803        if (expression instanceof ColumnReference)
1804            return ((ColumnReference)expression).getTableNumber();
1805        else if (expression instanceof VirtualColumnNode)
1806        {
1807            VirtualColumnNode vcn = (VirtualColumnNode)expression;
1808
1809            // If the VCN points to a FromBaseTable, just get that
1810
// table's number.
1811
if (vcn.getSourceResultSet() instanceof FromBaseTable)
1812            {
1813                return ((FromBaseTable)vcn.getSourceResultSet()).
1814                    getTableNumber();
1815            }
1816
1817            // Else recurse down the VCN.
1818
return vcn.getSourceColumn().getTableNumber();
1819        }
1820
1821        // We can get here if expression has neither a column
1822
// reference nor a FromBaseTable beneath it--for example,
1823
// if it is of type BaseColumnNode.
1824
return -1;
1825    }
1826    
1827    public boolean isEquivalent(ValueNode o) throws StandardException
1828    {
1829        if (o.getNodeType() == getNodeType())
1830        {
1831            ResultColumn other = (ResultColumn)o;
1832            if (expression != null) {
1833                return expression.isEquivalent(other.expression);
1834            }
1835        }
1836        return false;
1837    }
1838
1839}
1840
Popular Tags