KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.ResultSetNode
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.context.ContextManager;
25
26 import org.apache.derby.iapi.error.StandardException;
27 import org.apache.derby.iapi.sql.compile.CompilerContext;
28 import org.apache.derby.iapi.sql.compile.CostEstimate;
29 import org.apache.derby.iapi.sql.compile.OptimizerFactory;
30 import org.apache.derby.iapi.sql.compile.Optimizer;
31 import org.apache.derby.iapi.sql.compile.OptimizableList;
32 import org.apache.derby.iapi.sql.compile.OptimizablePredicateList;
33 import org.apache.derby.iapi.sql.compile.Parser;
34 import org.apache.derby.iapi.sql.compile.Visitable;
35 import org.apache.derby.iapi.sql.compile.Visitor;
36 import org.apache.derby.iapi.sql.compile.RequiredRowOrdering;
37 import org.apache.derby.iapi.sql.compile.RowOrdering;
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.DataDictionary;
44 import org.apache.derby.iapi.sql.dictionary.DefaultDescriptor;
45 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
46
47 import org.apache.derby.iapi.sql.execute.ExecutionContext;
48
49 import org.apache.derby.iapi.sql.Activation;
50 import org.apache.derby.iapi.types.DataTypeDescriptor;
51 import org.apache.derby.iapi.sql.ResultColumnDescriptor;
52 import org.apache.derby.iapi.sql.ResultDescription;
53 import org.apache.derby.iapi.sql.ResultSet;
54
55 import org.apache.derby.iapi.types.TypeId;
56
57 import org.apache.derby.iapi.store.access.TransactionController;
58
59 import org.apache.derby.iapi.services.loader.GeneratedMethod;
60
61 import org.apache.derby.iapi.services.sanity.SanityManager;
62 import org.apache.derby.iapi.reference.ClassName;
63
64 import org.apache.derby.iapi.services.compiler.MethodBuilder;
65
66 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
67 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
68
69 import org.apache.derby.iapi.util.JBitSet;
70 import org.apache.derby.iapi.services.classfile.VMOpcode;
71
72 import org.apache.derby.catalog.types.DefaultInfoImpl;
73
74 import java.util.Properties JavaDoc;
75 import java.util.Vector JavaDoc;
76 import java.util.Set JavaDoc;
77
78 /**
79  * A ResultSetNode represents a result set, that is, a set of rows. It is
80  * analogous to a ResultSet in the LanguageModuleExternalInterface. In fact,
81  * code generation for a a ResultSetNode will create a "new" call to a
82  * constructor for a ResultSet.
83  *
84  * @author Jeff Lichtman
85  */

86
87 public abstract class ResultSetNode extends QueryTreeNode
88 {
89     int resultSetNumber;
90     /* Bit map of referenced tables under this ResultSetNode */
91     JBitSet referencedTableMap;
92     ResultColumnList resultColumns;
93     boolean statementResultSet;
94     boolean cursorTargetTable;
95     boolean insertSource;
96
97     CostEstimate costEstimate;
98     CostEstimate scratchCostEstimate;
99     Optimizer optimizer;
100
101     // Final cost estimate for this result set node, which is the estimate
102
// for this node with respect to the best join order for the top-level
103
// query. Subclasses will set this value where appropriate.
104
CostEstimate finalCostEstimate;
105
106     /**
107      * Convert this object to a String. See comments in QueryTreeNode.java
108      * for how this should be done for tree printing.
109      *
110      * @return This object as a String
111      */

112
113     public String JavaDoc toString()
114     {
115         if (SanityManager.DEBUG)
116         {
117             return "resultSetNumber: " + resultSetNumber + "\n" +
118                 "referencedTableMap: " +
119                 (referencedTableMap != null
120                         ? referencedTableMap.toString()
121                         : "null") + "\n" +
122                 "statementResultSet: " + statementResultSet + "\n" +
123                 super.toString();
124         }
125         else
126         {
127             return "";
128         }
129     }
130
131     /**
132      * Prints the sub-nodes of this object. See QueryTreeNode.java for
133      * how tree printing is supposed to work.
134      *
135      * @param depth The depth of this node in the tree
136      */

137
138     public void printSubNodes(int depth)
139     {
140         if (SanityManager.DEBUG)
141         {
142             super.printSubNodes(depth);
143
144             if (resultColumns != null)
145             {
146                 printLabel(depth, "resultColumns: ");
147                 resultColumns.treePrint(depth);
148             }
149         }
150     }
151
152     /**
153      * Get the resultSetNumber in this ResultSetNode. Expected to be set during
154      * generate().
155      *
156      * @return int The resultSetNumber.
157      */

158
159     public int getResultSetNumber()
160     {
161         return resultSetNumber;
162     }
163
164     /**
165      * Get the CostEstimate for this ResultSetNode.
166      *
167      * @return The CostEstimate for this ResultSetNode.
168      */

169     public CostEstimate getCostEstimate()
170     {
171         if (SanityManager.DEBUG)
172         {
173             if (costEstimate == null)
174             {
175                 SanityManager.THROWASSERT(
176                     "costEstimate is not expected to be null for " +
177                     getClass().getName());
178             }
179         }
180         return costEstimate;
181     }
182
183     /**
184      * Get the final CostEstimate for this ResultSetNode.
185      *
186      * @return The final CostEstimate for this ResultSetNode.
187      */

188     public CostEstimate getFinalCostEstimate()
189         throws StandardException
190     {
191         if (SanityManager.DEBUG)
192         {
193             if (finalCostEstimate == null)
194             {
195                 SanityManager.THROWASSERT(
196                     "finalCostEstimate is not expected to be null for " +
197                     getClass().getName());
198             }
199         }
200         return finalCostEstimate;
201     }
202
203     /**
204      * Assign the next resultSetNumber to the resultSetNumber in this ResultSetNode.
205      * Expected to be done during generate().
206      *
207      * @exception StandardException Thrown on error
208      */

209
210     public void assignResultSetNumber() throws StandardException
211     {
212         resultSetNumber = getCompilerContext().getNextResultSetNumber();
213         resultColumns.setResultSetNumber(resultSetNumber);
214     }
215
216     /**
217      * Bind the non VTI tables in this ResultSetNode. This includes getting their
218      * descriptors from the data dictionary and numbering them.
219      *
220      * @param dataDictionary The DataDictionary to use for binding
221      * @param fromListParam FromList to use/append to.
222      *
223      * @return ResultSetNode
224      *
225      * @exception StandardException Thrown on error
226      */

227
228     public ResultSetNode bindNonVTITables(DataDictionary dataDictionary,
229                             FromList fromListParam)
230                             throws StandardException {
231         return this;
232     }
233
234
235     /**
236      * Bind the VTI tables in this ResultSetNode. This includes getting their
237      * descriptors from the data dictionary and numbering them.
238      *
239      * @param fromListParam FromList to use/append to.
240      *
241      * @return ResultSetNode
242      *
243      * @exception StandardException Thrown on error
244      */

245
246     public ResultSetNode bindVTITables(FromList fromListParam)
247         throws StandardException {
248         return this;
249     }
250
251     /**
252      * Bind the expressions in this ResultSetNode. This means binding the
253      * sub-expressions, as well as figuring out what the return type is for
254      * each expression.
255      *
256      * @param fromListParam FromList to use/append to.
257      *
258      * @exception StandardException Thrown on error
259      */

260     public void bindExpressions(FromList fromListParam)
261                     throws StandardException
262     {
263         if (SanityManager.DEBUG)
264         SanityManager.ASSERT(false,
265                     "bindExpressions() is not expected to be called for " +
266                     this.getClass().toString());
267     }
268
269     /**
270      * Bind the expressions in this ResultSetNode if it has tables. This means binding the
271      * sub-expressions, as well as figuring out what the return type is for
272      * each expression.
273      *
274      * @param fromListParam FromList to use/append to.
275      *
276      * @exception StandardException Thrown on error
277      */

278     public void bindExpressionsWithTables(FromList fromListParam)
279                     throws StandardException
280     {
281         if (SanityManager.DEBUG)
282         SanityManager.ASSERT(false,
283                     "bindExpressionsWithTables() is not expected to be called for " +
284                     this.getClass().toString());
285     }
286
287     /**
288      * Bind the expressions in the target list. This means binding the
289      * sub-expressions, as well as figuring out what the return type is
290      * for each expression. This is useful for EXISTS subqueries, where we
291      * need to validate the target list before blowing it away and replacing
292      * it with a SELECT true.
293      *
294      * @exception StandardException Thrown on error
295      */

296
297     public void bindTargetExpressions(FromList fromListParam)
298                     throws StandardException
299     {
300         if (SanityManager.DEBUG)
301         SanityManager.ASSERT(false,
302                     "bindTargetExpressions() is not expected to be called for " +
303                     this.getClass().toString());
304     }
305
306     /**
307      * Set the type of each parameter in the result column list for this table constructor.
308      *
309      * @param typeColumns The ResultColumnList containing the desired result
310      * types.
311      *
312      * @exception StandardException Thrown on error
313      */

314     void setTableConstructorTypes(ResultColumnList typeColumns)
315             throws StandardException
316     {
317         if (SanityManager.DEBUG)
318             SanityManager.ASSERT(resultColumns.size() <= typeColumns.size(),
319                 "More columns in ResultColumnList than in base table");
320
321         /* Look for ? parameters in the result column list */
322         int rclSize = resultColumns.size();
323         for (int index = 0; index < rclSize; index++)
324         {
325             ResultColumn rc = (ResultColumn) resultColumns.elementAt(index);
326
327             ValueNode re = rc.getExpression();
328
329             if (re.requiresTypeFromContext())
330             {
331                 ResultColumn typeCol =
332                     (ResultColumn) typeColumns.elementAt(index);
333
334                 /*
335                 ** We found a ? - set its type to the type of the
336                 ** corresponding column of the target table.
337                 */

338                 re.setType(typeCol.getTypeServices());
339             }
340             else if (re instanceof CharConstantNode)
341             {
342                 // Character constants are of type CHAR (fixed length string).
343
// This causes a problem (beetle 5160) when multiple row values are provided
344
// as constants for insertion into a variable length string column.
345
//
346
// This issue is the query expression
347
// VALUES 'abc', 'defghi'
348
// has type of CHAR(6), ie. the length of largest row value for that column.
349
// This is from the UNION defined behaviour.
350
// This causes strings with less than the maximum length to be blank padded
351
// to that length (CHAR semantics). Thus if this VALUES clause is used to
352
// insert into a variable length string column, then these blank padded values
353
// are inserted, which is not what is required ...
354
//
355
// BECAUSE, when the VALUES is used as a table constructor SQL standard says the
356
// types of the table constructor's columns are set by the table's column types.
357
// Thus, in this case, each of those string constants should be of type VARCHAR
358
// (or the matching string type for the table).
359
//
360
//
361
// This is only an issue for fixed length character (CHAR, BIT) string or
362
// binary consraints being inserted into variable length types.
363
// This is because any other type's fundemental literal value is not affected
364
// by its data type. E.g. Numeric types such as INT, REAL, BIGINT, DECIMAL etc.
365
// do not have their value modifed by the union since even if the type is promoted
366
// to a higher type, its fundemental value remains unchanged.
367
// values (1.2, 34.4567, 234.47) will be promoted to
368
// values (1.2000, 34.4567, 234.4700)
369
// but their numeric value remains the same.
370
//
371
//
372
//
373
// The fix is to change the base type of the table constructor's value to
374
// match the column type. Its length can be left as-is, because there is
375
// still a normailzation step when the value is inserted into the table.
376
// That will set the correct length and perform truncation checks etc.
377

378                 ResultColumn typeCol =
379                     (ResultColumn) typeColumns.elementAt(index);
380
381                 TypeId colTypeId = typeCol.getTypeId();
382
383                 if (colTypeId.isStringTypeId()) {
384
385                     if (colTypeId.getJDBCTypeId() != java.sql.Types.CHAR) {
386
387                         int maxWidth = re.getTypeServices().getMaximumWidth();
388
389                         re.setType(new DataTypeDescriptor(colTypeId, true, maxWidth));
390                     }
391                 }
392                 else if (colTypeId.isBitTypeId()) {
393                     if (colTypeId.getJDBCTypeId() == java.sql.Types.VARBINARY) {
394                     // then we're trying to cast a char literal into a
395
// variable bit column. We can't change the base
396
// type of the table constructor's value from char
397
// to bit, so instead, we just change the base type
398
// of that value from char to varchar--that way,
399
// no padding will be added when we convert to
400
// bits later on (Beetle 5306).
401
TypeId tId = TypeId.getBuiltInTypeId(java.sql.Types.VARCHAR);
402                         re.setType(new DataTypeDescriptor(tId, true));
403                         typeColumns.setElementAt(typeCol, index);
404                     }
405                     else if (colTypeId.getJDBCTypeId() == java.sql.Types.LONGVARBINARY) {
406                         TypeId tId = TypeId.getBuiltInTypeId(java.sql.Types.LONGVARCHAR);
407                         re.setType(new DataTypeDescriptor(tId, true));
408                         typeColumns.setElementAt(typeCol, index);
409                     }
410                 }
411
412             }
413             else if (re instanceof BitConstantNode)
414             {
415                 ResultColumn typeCol =
416                     (ResultColumn) typeColumns.elementAt(index);
417
418                 TypeId colTypeId = typeCol.getTypeId();
419
420                 if (colTypeId.isBitTypeId()) {
421
422                     // NOTE: Don't bother doing this if the column type is BLOB,
423
// as we don't allow bit literals to be inserted into BLOB
424
// columns (they have to be explicitly casted first); beetle 5266.
425
if ((colTypeId.getJDBCTypeId() != java.sql.Types.BINARY) &&
426                         (colTypeId.getJDBCTypeId() != java.sql.Types.BLOB)) {
427
428                         int maxWidth = re.getTypeServices().getMaximumWidth();
429
430                         re.setType(new DataTypeDescriptor(colTypeId, true, maxWidth));
431                     }
432                 }
433                 else if (colTypeId.isStringTypeId()) {
434                     if (colTypeId.getJDBCTypeId() == java.sql.Types.VARCHAR) {
435                     // then we're trying to cast a bit literal into a
436
// variable char column. We can't change the base
437
// type of the table constructor's value from bit
438
// to char, so instead, we just change the base
439
// type of that value from bit to varbit--that way,
440
// no padding will be added when we convert to
441
// char later on.
442
TypeId tId = TypeId.getBuiltInTypeId(java.sql.Types.VARBINARY);
443                         re.setType(new DataTypeDescriptor(tId, true));
444                         typeColumns.setElementAt(typeCol, index);
445                     }
446                     else if (colTypeId.getJDBCTypeId() == java.sql.Types.LONGVARCHAR) {
447                         TypeId tId = TypeId.getBuiltInTypeId(java.sql.Types.LONGVARBINARY);
448                         re.setType(new DataTypeDescriptor(tId, true));
449                         typeColumns.setElementAt(typeCol, index);
450                     }
451                 }
452             }
453         }
454     }
455
456     /**
457      * Remember that this node is the source result set for an INSERT.
458      */

459     public void setInsertSource()
460     {
461         insertSource = true;
462     }
463
464     /**
465      * Verify that a SELECT * is valid for this type of subquery.
466      *
467      * @param outerFromList The FromList from the outer query block(s)
468      * @param subqueryType The subquery type
469      *
470      * @exception StandardException Thrown on error
471      */

472     public void verifySelectStarSubquery(FromList outerFromList, int subqueryType)
473                     throws StandardException
474 {
475         if (SanityManager.DEBUG)
476         SanityManager.ASSERT(false,
477                     "verifySelectStarSubquery() is not expected to be called for " +
478                     this.getClass().toString());
479     }
480
481     /**
482      * Expand "*" into a ResultColumnList with all of the columns
483      * in the table's result list.
484      *
485      * @param allTableName The qualifier on the "*"
486      *
487      * @return ResultColumnList The expanded list
488      *
489      * @exception StandardException Thrown on error
490      */

491     public ResultColumnList getAllResultColumns(TableName allTableName)
492                     throws StandardException
493     {
494         if (SanityManager.DEBUG)
495         SanityManager.THROWASSERT(
496                              "getAllResultColumns() not expected to be called for " + this.getClass().getName() + this);
497         return null;
498     }
499
500     /**
501      * Try to find a ResultColumn in the table represented by this FromTable
502      * that matches the name in the given ColumnReference.
503      *
504      * @param columnReference The columnReference whose name we're looking
505      * for in the given table.
506      *
507      * @return A ResultColumn whose expression is the ColumnNode
508      * that matches the ColumnReference.
509      * Returns null if there is no match.
510      *
511      * @exception StandardException Thrown on error
512      */

513
514     public ResultColumn getMatchingColumn(
515                         ColumnReference columnReference)
516                         throws StandardException
517     {
518         if (SanityManager.DEBUG)
519         SanityManager.THROWASSERT(
520                              "getMatchingColumn() not expected to be called for " + this);
521         return null;
522     }
523
524     /**
525      * Set the result column for the subquery to a boolean true,
526      * Useful for transformations such as
527      * changing:
528      * where exists (select ... from ...)
529      * to:
530      * where (select true from ...)
531      *
532      * NOTE: No transformation is performed if the ResultColumn.expression is
533      * already the correct boolean constant.
534      *
535      * @param onlyConvertAlls Boolean, whether or not to just convert *'s
536      *
537      * @exception StandardException Thrown on error
538      */

539     public void setResultToBooleanTrueNode(boolean onlyConvertAlls)
540                 throws StandardException
541     {
542         BooleanConstantNode booleanNode;
543         ResultColumn resultColumn;
544
545         /* We need to be able to handle both ResultColumn and AllResultColumn
546          * since they are peers.
547          */

548         if (resultColumns.elementAt(0) instanceof AllResultColumn)
549         {
550             resultColumn = (ResultColumn) getNodeFactory().getNode(
551                                                 C_NodeTypes.RESULT_COLUMN,
552                                                 "",
553                                                 null,
554                                                 getContextManager());
555         }
556         else if (onlyConvertAlls)
557         {
558             return;
559         }
560         else
561         {
562             resultColumn = (ResultColumn) resultColumns.elementAt(0);
563     
564             /* Nothing to do if query is already select TRUE ... */
565             if (resultColumn.getExpression().isBooleanTrue())
566             {
567                 return;
568             }
569         }
570         
571         booleanNode = (BooleanConstantNode) getNodeFactory().getNode(
572                                         C_NodeTypes.BOOLEAN_CONSTANT_NODE,
573                                         Boolean.TRUE,
574                                         getContextManager());
575
576         resultColumn.setExpression(booleanNode);
577         resultColumn.setType(booleanNode.getTypeServices());
578         /* VirtualColumnIds are 1-based, RCLs are 0-based */
579         resultColumn.setVirtualColumnId(1);
580         resultColumns.setElementAt(resultColumn, 0);
581     }
582
583     /**
584      * Get the FromList. Create and return an empty FromList. (Subclasses
585      * which actuall have FromLists will override this.) This is useful because
586      * there is a FromList parameter to bindExpressions() which is used as
587      * the common FromList to bind against, allowing us to support
588      * correlation columns under unions in subqueries.
589      *
590      * @return FromList
591      * @exception StandardException Thrown on error
592      */

593     public FromList getFromList()
594         throws StandardException
595     {
596         return (FromList) getNodeFactory().getNode(
597                                     C_NodeTypes.FROM_LIST,
598                                     getNodeFactory().doJoinOrderOptimization(),
599                                     getContextManager());
600     }
601
602     /**
603      * @see QueryTreeNode#disablePrivilegeCollection
604      */

605     public void disablePrivilegeCollection()
606     {
607         super.disablePrivilegeCollection();
608         if (resultColumns != null)
609             resultColumns.disablePrivilegeCollection();
610     }
611
612     /**
613      * Bind the result columns of this ResultSetNode when there is no
614      * base table to bind them to. This is useful for SELECT statements,
615      * where the result columns get their types from the expressions that
616      * live under them.
617      *
618      * @param fromListParam FromList to use/append to.
619      *
620      * @exception StandardException Thrown on error
621      */

622
623     public void bindResultColumns(FromList fromListParam)
624                 throws StandardException
625     {
626         resultColumns.bindResultColumnsToExpressions();
627     }
628
629     /**
630      * Bind the result columns for this ResultSetNode to a base table.
631      * This is useful for INSERT and UPDATE statements, where the
632      * result columns get their types from the table being updated or
633      * inserted into.
634      * If a result column list is specified, then the verification that the
635      * result column list does not contain any duplicates will be done when
636      * binding them by name.
637      *
638      * @param targetTableDescriptor The TableDescriptor for the table being
639      * updated or inserted into
640      * @param targetColumnList For INSERT statements, the user
641      * does not have to supply column
642      * names (for example, "insert into t
643      * values (1,2,3)". When this
644      * parameter is null, it means that
645      * the user did not supply column
646      * names, and so the binding should
647      * be done based on order. When it
648      * is not null, it means do the binding
649      * by name, not position.
650      * @param statement Calling DMLStatementNode (Insert or Update)
651      * @param fromListParam FromList to use/append to.
652      *
653      * @exception StandardException Thrown on error
654      */

655
656     public void bindResultColumns(TableDescriptor targetTableDescriptor,
657                     FromVTI targetVTI,
658                     ResultColumnList targetColumnList,
659                     DMLStatementNode statement,
660                     FromList fromListParam)
661                 throws StandardException
662     {
663         /* For insert select, we need to expand any *'s in the
664          * select before binding the result columns
665          */

666         if (this instanceof SelectNode)
667         {
668             resultColumns.expandAllsAndNameColumns(((SelectNode)this).fromList);
669         }
670
671         /* If specified, copy the result column names down to the
672          * source's target list.
673          */

674         if (targetColumnList != null)
675         {
676             resultColumns.copyResultColumnNames(targetColumnList);
677         }
678
679         if (targetColumnList != null)
680         {
681             if (targetTableDescriptor != null)
682             {
683                 resultColumns.bindResultColumnsByName(
684                         targetTableDescriptor, (DMLStatementNode)statement);
685             }
686             else
687             {
688                 resultColumns.bindResultColumnsByName(
689                         targetVTI.getResultColumns(), targetVTI, statement);
690             }
691         }
692         else
693             resultColumns.bindResultColumnsByPosition(targetTableDescriptor);
694     }
695
696     /**
697      * Bind untyped nulls to the types in the given ResultColumnList.
698      * This is used for binding the nulls in row constructors and
699      * table constructors. In all other cases (as of the time of
700      * this writing), we do nothing.
701      *
702      * @param rcl The ResultColumnList with the types to bind nulls to
703      *
704      * @exception StandardException Thrown on error
705      */

706     public void bindUntypedNullsToResultColumns(ResultColumnList rcl)
707                 throws StandardException
708     {
709         return;
710     }
711
712     /**
713      * Preprocess a ResultSetNode - this currently means:
714      * o Generating a referenced table map for each ResultSetNode.
715      * o Putting the WHERE and HAVING clauses in conjunctive normal form (CNF).
716      * o Converting the WHERE and HAVING clauses into PredicateLists and
717      * classifying them.
718      * o Ensuring that a ProjectRestrictNode is generated on top of every
719      * FromBaseTable and generated in place of every FromSubquery.
720      * o Pushing single table predicates down to the new ProjectRestrictNodes.
721      *
722      * @param numTables The number of tables in the DML Statement
723      * @param gbl The group by list, if any
724      * @param fromList The from list, if any
725      *
726      * @return ResultSetNode at top of preprocessed tree.
727      *
728      * @exception StandardException Thrown on error
729      */

730
731     public ResultSetNode preprocess(int numTables,
732                                     GroupByList gbl,
733                                     FromList fromList)
734                                 throws StandardException
735     {
736         if (SanityManager.DEBUG)
737         SanityManager.THROWASSERT(
738                     "preprocess() not expected to be called for " + getClass().toString());
739         return null;
740     }
741
742     /**
743      * Find the unreferenced result columns and project them out.
744      */

745     void projectResultColumns() throws StandardException
746     {
747         // It is only necessary for joins
748
}
749
750     /**
751      * Ensure that the top of the RSN tree has a PredicateList.
752      *
753      * @param numTables The number of tables in the query.
754      * @return ResultSetNode A RSN tree with a node which has a PredicateList on top.
755      *
756      * @exception StandardException Thrown on error
757      */

758     public ResultSetNode ensurePredicateList(int numTables)
759         throws StandardException
760     {
761         if (SanityManager.DEBUG)
762         SanityManager.THROWASSERT(
763                     "ensurePredicateList() not expected to be called for " + getClass().toString());
764         return null;
765     }
766
767     /**
768      * Add a new predicate to the list. This is useful when doing subquery
769      * transformations, when we build a new predicate with the left side of
770      * the subquery operator and the subquery's result column.
771      *
772      * @param predicate The predicate to add
773      *
774      * @return ResultSetNode The new top of the tree.
775      *
776      * @exception StandardException Thrown on error
777      */

778     public ResultSetNode addNewPredicate(Predicate predicate)
779             throws StandardException
780     {
781         if (SanityManager.DEBUG)
782         SanityManager.THROWASSERT(
783                     "addNewPredicate() not expected to be called for " + getClass().toString());
784         return null;
785     }
786
787     /**
788      * Evaluate whether or not the subquery in a FromSubquery is flattenable.
789      * Currently, a FSqry is flattenable if all of the following are true:
790      * o Subquery is a SelectNode. (ie, not a RowResultSetNode or a UnionNode)
791      * o It contains no top level subqueries. (RESOLVE - we can relax this)
792      * o It does not contain a group by or having clause
793      * o It does not contain aggregates.
794      *
795      * @param fromList The outer from list
796      *
797      * @return boolean Whether or not the FromSubquery is flattenable.
798      */

799     public boolean flattenableInFromSubquery(FromList fromList)
800     {
801         if (SanityManager.DEBUG)
802         SanityManager.THROWASSERT(
803                     "flattenableInFromSubquery() not expected to be called for " + getClass().toString());
804         return false;
805     }
806
807     /**
808      * Get a parent ProjectRestrictNode above us.
809      * This is useful when we need to preserve the
810      * user specified column order when reordering the
811      * columns in the distinct when we combine
812      * an order by with a distinct.
813      *
814      * @return A parent ProjectRestrictNode to do column reordering
815      *
816      * @exception StandardException Thrown on error
817      */

818     ResultSetNode genProjectRestrictForReordering()
819                 throws StandardException
820     {
821         ResultColumnList prRCList;
822
823         /* We get a shallow copy of the ResultColumnList and its
824          * ResultColumns. (Copy maintains ResultColumn.expression for now.)
825          */

826         prRCList = resultColumns;
827         resultColumns = resultColumns.copyListAndObjects();
828
829         /* Replace ResultColumn.expression with new VirtualColumnNodes
830          * in the ProjectRestrictNode's ResultColumnList. (VirtualColumnNodes include
831          * pointers to source ResultSetNode, this, and source ResultColumn.)
832          * NOTE: We don't want to mark the underlying RCs as referenced, otherwise
833          * we won't be able to project out any of them.
834          */

835         prRCList.genVirtualColumnNodes(this, resultColumns, false);
836
837         /* Finally, we create the new ProjectRestrictNode */
838         return (ResultSetNode) getNodeFactory().getNode(
839                                 C_NodeTypes.PROJECT_RESTRICT_NODE,
840                                 this,
841                                 prRCList,
842                                 null, /* Restriction */
843                                 null, /* Restriction as PredicateList */
844                                 null, /* Project subquery list */
845                                 null, /* Restrict subquery list */
846                                 null,
847                                 getContextManager() );
848     }
849
850     /**
851      * Optimize a ResultSetNode. This means choosing the best access
852      * path for each table under the ResultSetNode, among other things.
853      *
854      * The only RSNs that need to implement their own optimize() are a
855      * SelectNode and those RSNs that can appear above a SelectNode in the
856      * query tree. Currently, a ProjectRestrictNode is the only RSN that
857      * can appear above a SelectNode.
858      *
859      * @param dataDictionary The DataDictionary to use for optimization
860      * @param predicates The PredicateList to apply.
861      * @param outerRows The number of outer joining rows
862      *
863      * @return ResultSetNode The top of the optimized query tree
864      *
865      * @exception StandardException Thrown on error
866      */

867
868     public ResultSetNode optimize(DataDictionary dataDictionary,
869                                   PredicateList predicates,
870                                   double outerRows)
871                 throws StandardException
872     {
873         if (SanityManager.DEBUG)
874         SanityManager.ASSERT(false,
875                     "optimize() is not expected to be called for " +
876                     this.getClass().toString());
877         return null;
878     }
879
880     /**
881      * Modify the access paths according to the decisions the optimizer
882      * made. This can include adding project/restrict nodes,
883      * index-to-base-row nodes, etc.
884      *
885      * @return The modified query tree
886      *
887      * @exception StandardException Thrown on error
888      */

889     public ResultSetNode modifyAccessPaths() throws StandardException
890     {
891         /* Default behavior is to do nothing */
892         return this;
893     }
894
895     /**
896      * Modify the access paths according to the decisions the optimizer
897      * made. This can include adding project/restrict nodes,
898      * index-to-base-row nodes, etc.
899      *
900      * @param predList A list of optimizable predicates that should
901      * be pushed to this ResultSetNode, as determined by optimizer.
902      * @return The modified query tree
903      * @exception StandardException Thrown on error
904      */

905     public ResultSetNode modifyAccessPaths(PredicateList predList)
906         throws StandardException
907     {
908         // Default behavior is to call the no-arg version of this method.
909
return modifyAccessPaths();
910     }
911
912     ResultColumnDescriptor[] makeResultDescriptors(ExecutionContext ec)
913     {
914         return resultColumns.makeResultDescriptors(ec);
915     }
916
917     /*
918     ** Check whether the column lengths and types of the result columns
919     ** match the expressions under those columns. This is useful for
920     ** INSERT and UPDATE statements. For SELECT statements this method
921     ** should always return true. There is no need to call this for a
922     ** DELETE statement.
923     **
924     ** @return true means all the columns match their expressions,
925     ** false means at least one column does not match its
926     ** expression
927     */

928
929     boolean columnTypesAndLengthsMatch()
930         throws StandardException
931     {
932         return resultColumns.columnTypesAndLengthsMatch();
933     }
934
935     /**
936      * Set the resultColumns in this ResultSetNode
937      *
938      * @param newRCL The new ResultColumnList for this ResultSetNode
939      */

940     public void setResultColumns(ResultColumnList newRCL)
941     {
942         resultColumns = newRCL;
943     }
944
945     /**
946      * Get the resultColumns for this ResultSetNode
947      *
948      * @return ResultColumnList for this ResultSetNode
949      */

950     public ResultColumnList getResultColumns()
951     {
952         return resultColumns;
953     }
954
955     /**
956      * Set the referencedTableMap in this ResultSetNode
957      *
958      * @param newRTM The new referencedTableMap for this ResultSetNode
959      */

960     public void setReferencedTableMap(JBitSet newRTM)
961     {
962         referencedTableMap = newRTM;
963     }
964
965     /**
966      * Get the referencedTableMap for this ResultSetNode
967      *
968      * @return JBitSet Referenced table map for this ResultSetNode
969      */

970     public JBitSet getReferencedTableMap()
971     {
972         return referencedTableMap;
973     }
974
975     /**
976      * Fill the referencedTableMap with this ResultSetNode.
977      *
978      * @param passedMap The table map to fill in.
979      */

980     public void fillInReferencedTableMap(JBitSet passedMap)
981     {
982     }
983
984     /**
985      * Check for (and reject) ? parameters directly under the ResultColumns.
986      * This is done for SELECT statements.
987      *
988      * @exception StandardException Thrown if a ? parameter found
989      * directly under a ResultColumn
990      */

991
992     public void rejectParameters() throws StandardException
993     {
994         /* Okay if no resultColumns yet - means no parameters there */
995         if (resultColumns != null)
996         {
997             resultColumns.rejectParameters();
998         }
999     }
1000
1001    /**
1002     * Check for (and reject) XML values directly under the ResultColumns.
1003     * This is done for SELECT/VALUES statements. We reject values
1004     * in this case because JDBC does not define an XML type/binding
1005     * and thus there's no standard way to pass such a type back
1006     * to a JDBC application.
1007     *
1008     * @exception StandardException Thrown if an XML value found
1009     * directly under a ResultColumn
1010     */

1011    public void rejectXMLValues() throws StandardException
1012    {
1013        if (resultColumns != null)
1014        {
1015            resultColumns.rejectXMLValues();
1016        }
1017    }
1018
1019    /**
1020     * Rename generated result column names as '1', '2' etc... These will be the result
1021     * column names seen by JDBC clients.
1022     */

1023    public void renameGeneratedResultNames() throws StandardException
1024    {
1025        for (int i=0; i<resultColumns.size(); i++)
1026        {
1027            ResultColumn rc = (ResultColumn) resultColumns.elementAt(i);
1028            if (rc.isNameGenerated())
1029                rc.setName(Integer.toString(i+1));
1030        }
1031    }
1032
1033    /**
1034        This method is overridden to allow a resultset node to know
1035        if it is the one controlling the statement -- i.e., it is
1036        the outermost result set node for the statement.
1037     */

1038    public void markStatementResultSet()
1039    {
1040        statementResultSet = true;
1041    }
1042
1043    /**
1044     * This ResultSet is the source for an Insert. The target RCL
1045     * is in a different order and/or a superset of this RCL. In most cases
1046     * we will reorder and/or add defaults to the current RCL so that is
1047     * matches the target RCL. Those RSNs whose generate() method does
1048     * not handle projects will insert a PRN, with a new RCL which matches
1049     * the target RCL, above the current RSN.
1050     * NOTE - The new or enhanced RCL will be fully bound.
1051     *
1052     * @param numTargetColumns # of columns in target RCL
1053     * @param colMap int array representation of correspondence between
1054     * RCLs - colmap[i] = -1 -> missing in current RCL
1055     * colmap[i] = j -> targetRCL(i) <-> thisRCL(j+1)
1056     * @param dataDictionary DataDictionary to use
1057     * @param targetTD TableDescriptor for target if the target is not a VTI, null if a VTI
1058     * @param targetVTI Target description if it is a VTI, null if not a VTI
1059     *
1060     * @return ResultSetNode The new top of the tree
1061     *
1062     * @exception StandardException Thrown on error
1063     */

1064    public ResultSetNode enhanceRCLForInsert(int numTargetColumns, int[] colMap,
1065                                             DataDictionary dataDictionary,
1066                                             TableDescriptor targetTD,
1067                                             FromVTI targetVTI)
1068            throws StandardException
1069    {
1070        // our newResultCols are put into the bound form straight away.
1071
ResultColumnList newResultCols =
1072                            (ResultColumnList) getNodeFactory().getNode(
1073                                                C_NodeTypes.RESULT_COLUMN_LIST,
1074                                                getContextManager());
1075        int numResultSetColumns = resultColumns.size();
1076
1077        /* Create a massaged version of the source RCL.
1078         * (Much simpler to build new list and then assign to source,
1079         * rather than massage the source list in place.)
1080         */

1081        for (int index = 0; index < numTargetColumns; index++)
1082        {
1083            ResultColumn newResultColumn = null;
1084            ColumnReference newColumnReference;
1085
1086            if (colMap[index] != -1)
1087            {
1088                // getResultColumn uses 1-based positioning, so offset the colMap entry appropriately
1089
newResultColumn = resultColumns.getResultColumn(colMap[index]+1);
1090            }
1091            else
1092            {
1093                newResultColumn = genNewRCForInsert(targetTD, targetVTI, index + 1, dataDictionary);
1094            }
1095
1096            newResultCols.addResultColumn(newResultColumn);
1097        }
1098
1099        /* Set the source RCL to the massaged version */
1100        resultColumns = newResultCols;
1101
1102        return this;
1103    }
1104
1105    /**
1106     * Generate the RC/expression for an unspecified column in an insert.
1107     * Use the default if one exists.
1108     *
1109     * @param targetTD Target TableDescriptor if the target is not a VTI, null if a VTI.
1110     * @param targetVTI Target description if it is a VTI, null if not a VTI
1111     * @param columnNumber The column number
1112     * @param dataDictionary The DataDictionary
1113     * @return The RC/expression for the unspecified column.
1114     *
1115     * @exception StandardException Thrown on error
1116     */

1117    ResultColumn genNewRCForInsert(TableDescriptor targetTD,
1118                                   FromVTI targetVTI,
1119                                   int columnNumber,
1120                                   DataDictionary dataDictionary)
1121        throws StandardException
1122    {
1123        ResultColumn newResultColumn = null;
1124
1125        // the i-th column's value was not specified, so create an
1126
// expression containing its default value (null for now)
1127
// REVISIT: will we store trailing nulls?
1128

1129        if( targetVTI != null)
1130        {
1131            newResultColumn = targetVTI.getResultColumns().getResultColumn( columnNumber);
1132            newResultColumn = newResultColumn.cloneMe();
1133            newResultColumn.setExpressionToNullNode();
1134        }
1135        else
1136        {
1137            // column position is 1-based, index is 0-based.
1138
ColumnDescriptor colDesc = targetTD.getColumnDescriptor(columnNumber);
1139            DataTypeDescriptor colType = colDesc.getType();
1140
1141            // Check for defaults
1142
DefaultInfoImpl defaultInfo = (DefaultInfoImpl) colDesc.getDefaultInfo();
1143        
1144        //Column has constant default value ,
1145
//if it have defaultInfo and not be autoincrement.
1146
if (defaultInfo != null && ! colDesc.isAutoincrement())
1147            {
1148                //RESOLVEPARAMETER - skip the tree if we have the value
1149
/*
1150                  if (defaultInfo.getDefaultValue() != null)
1151                  {
1152                  }
1153                  else
1154                */

1155                {
1156                    // Generate the tree for the default
1157
String JavaDoc defaultText = defaultInfo.getDefaultText();
1158                    ValueNode defaultTree = parseDefault(defaultText);
1159                    defaultTree = defaultTree.bindExpression(
1160                        getFromList(),
1161                        (SubqueryList) null,
1162                        (Vector JavaDoc) null);
1163                    newResultColumn = (ResultColumn) getNodeFactory().getNode(
1164                        C_NodeTypes.RESULT_COLUMN,
1165                        defaultTree.getTypeServices(),
1166                        defaultTree,
1167                        getContextManager());
1168
1169                    DefaultDescriptor defaultDescriptor = colDesc.getDefaultDescriptor(dataDictionary);
1170                    if (SanityManager.DEBUG)
1171                    {
1172                        SanityManager.ASSERT(defaultDescriptor != null,
1173                                             "defaultDescriptor expected to be non-null");
1174                    }
1175                    getCompilerContext().createDependency(defaultDescriptor);
1176                }
1177            }
1178            else if (colDesc.isAutoincrement())
1179            {
1180                newResultColumn =
1181                  (ResultColumn)getNodeFactory().getNode(
1182                      C_NodeTypes.RESULT_COLUMN,
1183                      colDesc, null,
1184                      getContextManager());
1185                newResultColumn.setAutoincrementGenerated();
1186            }
1187            else
1188            {
1189                newResultColumn = (ResultColumn) getNodeFactory().getNode(
1190                    C_NodeTypes.RESULT_COLUMN,
1191                    colType,
1192                    getNullNode(
1193                        colType.getTypeId(),
1194                        getContextManager()
1195                        ),
1196                    getContextManager()
1197                    );
1198            }
1199        }
1200
1201        // Mark the new RC as generated for an unmatched column in an insert
1202
newResultColumn.markGeneratedForUnmatchedColumnInInsert();
1203
1204        return newResultColumn;
1205    }
1206
1207    /**
1208      * Parse a default and turn it into a query tree.
1209      *
1210      * @param defaultText Text of Default.
1211      *
1212      * @return The parsed default as a query tree.
1213      *
1214      * @exception StandardException Thrown on failure
1215      */

1216    public ValueNode parseDefault
1217    (
1218        String JavaDoc defaultText
1219    )
1220        throws StandardException
1221    {
1222        Parser p;
1223        ValueNode defaultTree;
1224        LanguageConnectionContext lcc = getLanguageConnectionContext();
1225        CompilerContext compilerContext = getCompilerContext();
1226
1227        /* Get a Statement to pass to the parser */
1228
1229        /* We're all set up to parse. We have to build a compilable SQL statement
1230         * before we can parse - So, we goober up a VALUES defaultText.
1231         */

1232        String JavaDoc values = "VALUES " + defaultText;
1233        
1234        /*
1235        ** Get a new compiler context, so the parsing of the select statement
1236        ** doesn't mess up anything in the current context (it could clobber
1237        ** the ParameterValueSet, for example).
1238        */

1239        CompilerContext newCC = lcc.pushCompilerContext();
1240
1241        p = newCC.getParser();
1242                
1243        /* Finally, we can call the parser */
1244        // Since this is always nested inside another SQL statement, so topLevel flag
1245
// should be false
1246
QueryTreeNode qt = p.parseStatement(values);
1247        if (SanityManager.DEBUG)
1248        {
1249            if (! (qt instanceof CursorNode))
1250            {
1251                SanityManager.THROWASSERT(
1252                    "qt expected to be instanceof CursorNode, not " +
1253                    qt.getClass().getName());
1254            }
1255            CursorNode cn = (CursorNode) qt;
1256            if (! (cn.getResultSetNode() instanceof RowResultSetNode))
1257            {
1258                SanityManager.THROWASSERT(
1259                    "cn.getResultSetNode() expected to be instanceof RowResultSetNode, not " +
1260                    cn.getResultSetNode().getClass().getName());
1261            }
1262        }
1263
1264        defaultTree = ((ResultColumn)
1265                            ((CursorNode) qt).getResultSetNode().getResultColumns().elementAt(0)).
1266                                    getExpression();
1267
1268        lcc.popCompilerContext(newCC);
1269
1270        return defaultTree;
1271    }
1272
1273    /**
1274     * Make a ResultDescription for use in a ResultSet.
1275     * This is useful when generating/executing a NormalizeResultSet, since
1276     * it can appear anywhere in the tree.
1277     *
1278     * @return A ResultDescription for this ResultSetNode.
1279     */

1280
1281    public ResultDescription makeResultDescription()
1282    {
1283        ExecutionContext ec = (ExecutionContext) getContextManager().getContext(
1284            ExecutionContext.CONTEXT_ID);
1285        ResultColumnDescriptor[] colDescs = makeResultDescriptors(ec);
1286
1287        return ec.getExecutionFactory().getResultDescription(colDescs, null );
1288    }
1289
1290    /**
1291        Determine if this result set is updatable or not, for a cursor
1292        (i.e., is it a cursor-updatable select). This returns false
1293        and we expect selectnode to refine it for further checking.
1294     *
1295     * @exception StandardException Thrown on error
1296     */

1297    boolean isUpdatableCursor(DataDictionary dd) throws StandardException
1298    {
1299        if (SanityManager.DEBUG)
1300        SanityManager.DEBUG("DumpUpdateCheck","cursor is not a select result set");
1301        return false;
1302    }
1303
1304    /**
1305        return the target table of an updatable cursor result set.
1306        since this is not updatable, just return null.
1307     */

1308    FromTable getCursorTargetTable()
1309    {
1310        return null;
1311    }
1312
1313    /**
1314        Mark this ResultSetNode as the target table of an updatable
1315        cursor. Most types of ResultSetNode can't be target tables.
1316        @return true if the target table supports positioned updates.
1317     */

1318    public boolean markAsCursorTargetTable()
1319    {
1320        return false;
1321    }
1322
1323    /**
1324        Mark this ResultSetNode as *not* the target table of an updatable
1325        cursor.
1326     */

1327    void notCursorTargetTable()
1328    {
1329        cursorTargetTable = false;
1330    }
1331
1332    /**
1333     * Put a ProjectRestrictNode on top of this ResultSetNode.
1334     * ColumnReferences must continue to point to the same ResultColumn, so
1335     * that ResultColumn must percolate up to the new PRN. However,
1336     * that ResultColumn will point to a new expression, a VirtualColumnNode,
1337     * which points to the FromTable and the ResultColumn that is the source for
1338     * the ColumnReference.
1339     * (The new PRN will have the original of the ResultColumnList and
1340     * the ResultColumns from that list. The FromTable will get shallow copies
1341     * of the ResultColumnList and its ResultColumns. ResultColumn.expression
1342     * will remain at the FromTable, with the PRN getting a new
1343     * VirtualColumnNode for each ResultColumn.expression.)
1344     *
1345     * This is useful for UNIONs, where we want to generate a DistinctNode above
1346     * the UnionNode to eliminate the duplicates, because DistinctNodes expect
1347     * their immediate child to be a PRN.
1348     *
1349     * @return The generated ProjectRestrictNode atop the original ResultSetNode.
1350     *
1351     * @exception StandardException Thrown on error
1352     */

1353
1354    public ResultSetNode genProjectRestrict()
1355                throws StandardException
1356    {
1357        ResultColumnList prRCList;
1358
1359        /* We get a shallow copy of the ResultColumnList and its
1360         * ResultColumns. (Copy maintains ResultColumn.expression for now.)
1361         */

1362        prRCList = resultColumns;
1363        resultColumns = resultColumns.copyListAndObjects();
1364
1365        /* Replace ResultColumn.expression with new VirtualColumnNodes
1366         * in the ProjectRestrictNode's ResultColumnList. (VirtualColumnNodes include
1367         * pointers to source ResultSetNode, this, and source ResultColumn.)
1368         */

1369        prRCList.genVirtualColumnNodes(this, resultColumns);
1370
1371        /* Finally, we create the new ProjectRestrictNode */
1372        return (ResultSetNode) getNodeFactory().getNode(
1373                                C_NodeTypes.PROJECT_RESTRICT_NODE,
1374                                this,
1375                                prRCList,
1376                                null, /* Restriction */
1377                                null, /* Restriction as PredicateList */
1378                                null, /* Project subquery list */
1379                                null, /* Restrict subquery list */
1380                                null,
1381                                getContextManager() );
1382    }
1383
1384    /**
1385     * Put a ProjectRestrictNode on top of each FromTable in the FromList.
1386     * ColumnReferences must continue to point to the same ResultColumn, so
1387     * that ResultColumn must percolate up to the new PRN. However,
1388     * that ResultColumn will point to a new expression, a VirtualColumnNode,
1389     * which points to the FromTable and the ResultColumn that is the source for
1390     * the ColumnReference.
1391     * (The new PRN will have the original of the ResultColumnList and
1392     * the ResultColumns from that list. The FromTable will get shallow copies
1393     * of the ResultColumnList and its ResultColumns. ResultColumn.expression
1394     * will remain at the FromTable, with the PRN getting a new
1395     * VirtualColumnNode for each ResultColumn.expression.)
1396     * We then project out the non-referenced columns. If there are no referenced
1397     * columns, then the PRN's ResultColumnList will consist of a single ResultColumn
1398     * whose expression is 1.
1399     *
1400     * @param numTables Number of tables in the DML Statement
1401     *
1402     * @return The generated ProjectRestrictNode atop the original FromTable.
1403     *
1404     * @exception StandardException Thrown on error
1405     */

1406
1407    protected ResultSetNode genProjectRestrict(int numTables)
1408                throws StandardException
1409    {
1410        return genProjectRestrict();
1411    }
1412
1413    /**
1414     * Put a NormalizeResultSetNode on top of the specified ResultSetNode.
1415     * ColumnReferences must continue to point to the same ResultColumn, so
1416     * that ResultColumn must percolate up to the new PRN. However,
1417     * that ResultColumn will point to a new expression, a VirtualColumnNode,
1418     * which points to the FromTable and the ResultColumn that is the source for
1419     * the ColumnReference.
1420     * (The new NRSN will have the original of the ResultColumnList and
1421     * the ResultColumns from that list. The FromTable will get shallow copies
1422     * of the ResultColumnList and its ResultColumns. ResultColumn.expression
1423     * will remain at the FromTable, with the PRN getting a new
1424     * VirtualColumnNode for each ResultColumn.expression.)
1425     *
1426     * This is useful for UNIONs, where we want to generate a DistinctNode above
1427     * the UnionNode to eliminate the duplicates, because the type going into the
1428     * sort has to agree with what the sort expects.
1429     * (insert into t1 (smallintcol) values 1 union all values 2;
1430     *
1431     * @param normalizeChild Child result set for new NRSN.
1432     * @param forUpdate If the normalize result set is being used as a
1433     * child for an update statement, then this is true.
1434     *
1435     * @return The generated NormalizeResultSetNode atop the original UnionNode.
1436     *
1437     * @exception StandardException Thrown on error
1438     * @see NormalizeResultSetNode#init
1439     */

1440
1441    public NormalizeResultSetNode
1442        genNormalizeResultSetNode(ResultSetNode normalizeChild,
1443                                  boolean forUpdate)
1444                throws StandardException
1445    {
1446        NormalizeResultSetNode nrsn;
1447        ResultColumnList prRCList;
1448
1449        /* We get a shallow copy of the ResultColumnList and its
1450         * ResultColumns. (Copy maintains ResultColumn.expression for now.)
1451         */

1452        prRCList = resultColumns;
1453        resultColumns = resultColumns.copyListAndObjects();
1454
1455        /* Replace ResultColumn.expression with new VirtualColumnNodes
1456         * in the NormalizeResultSetNode's ResultColumnList. (VirtualColumnNodes include
1457         * pointers to source ResultSetNode, this, and source ResultColumn.)
1458         */

1459        prRCList.genVirtualColumnNodes(this, resultColumns);
1460
1461        /* Finally, we create the new NormalizeResultSetNode */
1462        nrsn = (NormalizeResultSetNode) getNodeFactory().getNode(
1463                                C_NodeTypes.NORMALIZE_RESULT_SET_NODE,
1464                                normalizeChild,
1465                                prRCList,
1466                                null, new Boolean JavaDoc(forUpdate),
1467                                getContextManager());
1468        // Propagate the referenced table map if it's already been created
1469
if (normalizeChild.getReferencedTableMap() != null)
1470        {
1471            nrsn.setReferencedTableMap((JBitSet) normalizeChild.getReferencedTableMap().clone());
1472        }
1473        return nrsn;
1474    }
1475
1476    /**
1477     * Generate the code for a NormalizeResultSet.
1478       The call must push two items before calling this method
1479       <OL>
1480       <LI> pushGetResultSetFactoryExpression
1481       <LI> the expression to normalize
1482       </OL>
1483     *
1484     * @param acb The ActivationClassBuilder
1485     * @param mb The method to put the generated code in
1486     * @param resultSetNumber The result set number for the NRS
1487     * @param resultDescription The ERD for the ResultSet
1488     *
1489     *
1490     * @exception StandardException Thrown on error
1491     */

1492    public void generateNormalizationResultSet(
1493                        ActivationClassBuilder acb,
1494                        MethodBuilder mb,
1495                        int resultSetNumber,
1496                        ResultDescription resultDescription)
1497            throws StandardException
1498    {
1499        int erdNumber = acb.addItem(resultDescription);
1500
1501        // instance and first arg are pushed by caller
1502

1503        mb.push(resultSetNumber);
1504        mb.push(erdNumber);
1505        mb.push(getCostEstimate().rowCount());
1506        mb.push(getCostEstimate().getEstimatedCost());
1507        mb.push(false);
1508
1509        mb.callMethod(VMOpcode.INVOKEINTERFACE, (String JavaDoc) null, "getNormalizeResultSet",
1510                    ClassName.NoPutResultSet, 6);
1511    }
1512
1513    /**
1514     * The optimizer's decision on the access path for a result set
1515     * may require the generation of extra result sets. For example,
1516     * if it chooses an index for a FromBaseTable, we need an IndexToBaseRowNode
1517     * above the FromBaseTable (and the FromBaseTable has to change its
1518     * column list to match the index.
1519     *
1520     * This method in the parent class does not generate any extra result sets.
1521     * It may be overridden in child classes.
1522     *
1523     * @return A ResultSetNode tree modified to do any extra processing for
1524     * the chosen access path
1525     *
1526     * @exception StandardException Thrown on error
1527     */

1528    public ResultSetNode changeAccessPath() throws StandardException
1529    {
1530        return this;
1531    }
1532
1533    /**
1534     * Search to see if a query references the specifed table name.
1535     *
1536     * @param name Table name (String) to search for.
1537     * @param baseTable Whether or not name is for a base table
1538     *
1539     * @return true if found, else false
1540     *
1541     * @exception StandardException Thrown on error
1542     */

1543    public boolean referencesTarget(String JavaDoc name, boolean baseTable)
1544        throws StandardException
1545    {
1546        return false;
1547    }
1548
1549    /**
1550     * Return whether or not this ResultSetNode contains a subquery with a
1551     * reference to the specified target.
1552     *
1553     * @param name The table name.
1554     *
1555     * @return boolean Whether or not a reference to the table was found.
1556     *
1557     * @exception StandardException Thrown on error
1558     */

1559    boolean subqueryReferencesTarget(String JavaDoc name, boolean baseTable)
1560        throws StandardException
1561    {
1562        return false;
1563    }
1564
1565    /**
1566     * Return whether or not the underlying ResultSet tree will return
1567     * a single row, at most.
1568     * This is important for join nodes where we can save the extra next
1569     * on the right side if we know that it will return at most 1 row.
1570     *
1571     * @return Whether or not the underlying ResultSet tree will return a single row.
1572     * @exception StandardException Thrown on error
1573     */

1574    public boolean isOneRowResultSet() throws StandardException
1575    {
1576        // Default is false
1577
return false;
1578    }
1579
1580    /**
1581     * Return whether or not the underlying ResultSet tree is for a NOT EXISTS
1582     * join.
1583     *
1584     * @return Whether or not the underlying ResultSet tree if for NOT EXISTS.
1585     */

1586    public boolean isNotExists()
1587    {
1588        // Default is false
1589
return false;
1590    }
1591
1592    /**
1593     * Get an optimizer to use for this ResultSetNode. Only get it once -
1594     * subsequent calls return the same optimizer.
1595     *
1596     * @exception StandardException Thrown on error
1597     */

1598    protected Optimizer getOptimizer(
1599                            OptimizableList optList,
1600                            OptimizablePredicateList predList,
1601                            DataDictionary dataDictionary,
1602                            RequiredRowOrdering requiredRowOrdering)
1603            throws StandardException
1604    {
1605        if (optimizer == null)
1606        {
1607            /* Get an optimizer. */
1608            OptimizerFactory optimizerFactory = getLanguageConnectionContext().getOptimizerFactory();
1609
1610            optimizer = optimizerFactory.getOptimizer(
1611                                            optList,
1612                                            predList,
1613                                            dataDictionary,
1614                                            requiredRowOrdering,
1615                                            getCompilerContext().getNumTables(),
1616                                getLanguageConnectionContext());
1617        }
1618
1619        optimizer.prepForNextRound();
1620        return optimizer;
1621    }
1622
1623    /**
1624     * Get the optimizer for this result set.
1625     *
1626     * @return If this.optimizer has has already been created by the
1627     * getOptimizer() method above, then return it; otherwise,
1628     * return null.
1629     */

1630    protected OptimizerImpl getOptimizerImpl()
1631    {
1632        // Note that the optimizer might be null because it's possible that
1633
// we'll get here before any calls to getOptimizer() were made, which
1634
// can happen if we're trying to save a "best path" but we haven't
1635
// actually found one yet. In that case we just return the "null"
1636
// value; the caller must check for it and behave appropriately.
1637
// Ex. see TableOperatorNode.addOrLoadBestPlanMapping().
1638
return (OptimizerImpl)optimizer;
1639    }
1640
1641    /**
1642     * Get a cost estimate to use for this ResultSetNode.
1643     *
1644     * @exception StandardException Thrown on error
1645     */

1646    protected CostEstimate getNewCostEstimate()
1647            throws StandardException
1648    {
1649        OptimizerFactory optimizerFactory = getLanguageConnectionContext().getOptimizerFactory();
1650        return optimizerFactory.getCostEstimate();
1651    }
1652
1653    /**
1654     * Accept a visitor, and call v.visit()
1655     * on child nodes as necessary.
1656     *
1657     * @param v the visitor
1658     *
1659     * @exception StandardException on error
1660     */

1661    public Visitable accept(Visitor v)
1662        throws StandardException
1663    {
1664        Visitable returnNode = v.visit(this);
1665
1666        if (v.skipChildren(this))
1667        {
1668            return returnNode;
1669        }
1670
1671        if (resultColumns != null && !v.stopTraversal())
1672        {
1673            resultColumns = (ResultColumnList)resultColumns.accept(v);
1674        }
1675        return returnNode;
1676    }
1677
1678    /**
1679     * Consider materialization for this ResultSet tree if it is valid and cost effective
1680     * (It is not valid if incorrect results would be returned.)
1681     *
1682     * @return Top of the new/same ResultSet tree.
1683     *
1684     * @exception StandardException Thrown on error
1685     */

1686    public ResultSetNode considerMaterialization(JBitSet outerTables)
1687        throws StandardException
1688    {
1689        return this;
1690    }
1691
1692    /**
1693     * Return whether or not to materialize this ResultSet tree.
1694     *
1695     * @return Whether or not to materialize this ResultSet tree.
1696     * would return valid results.
1697     *
1698     * @exception StandardException Thrown on error
1699     */

1700    public boolean performMaterialization(JBitSet outerTables)
1701        throws StandardException
1702    {
1703        return false;
1704    }
1705
1706    /**
1707     * Determine whether or not the specified name is an exposed name in
1708     * the current query block.
1709     *
1710     * @param name The specified name to search for as an exposed name.
1711     * @param schemaName Schema name, if non-null.
1712     * @param exactMatch Whether or not we need an exact match on specified schema and table
1713     * names or match on table id.
1714     *
1715     * @return The FromTable, if any, with the exposed name.
1716     *
1717     * @exception StandardException Thrown on error
1718     */

1719    protected FromTable getFromTableByName(String JavaDoc name, String JavaDoc schemaName, boolean exactMatch)
1720        throws StandardException
1721    {
1722        if (SanityManager.DEBUG)
1723        {
1724            SanityManager.THROWASSERT("getFromTableByName() not expected to be called for " +
1725                                      getClass().getName());
1726        }
1727        return null;
1728    }
1729
1730    /**
1731     * Decrement (query block) level (0-based) for
1732     * all of the tables in this ResultSet tree.
1733     * This is useful when flattening a subquery.
1734     *
1735     * @param decrement The amount to decrement by.
1736     */

1737    abstract void decrementLevel(int decrement);
1738
1739    /**
1740     * Push the order by list down from the cursor node
1741     * into its child result set so that the optimizer
1742     * has all of the information that it needs to
1743     * consider sort avoidance.
1744     *
1745     * @param orderByList The order by list
1746     */

1747    void pushOrderByList(OrderByList orderByList)
1748    {
1749        if (SanityManager.DEBUG)
1750        {
1751            SanityManager.THROWASSERT("pushOrderByList() not expected to be called for " +
1752                                      getClass().getName());
1753        }
1754    }
1755
1756    /**
1757     * General logic shared by Core compilation and by the Replication Filter
1758     * compiler. A couple ResultSets (the ones used by PREPARE SELECT FILTER)
1759     * implement this method.
1760     *
1761     * @param acb The ExpressionClassBuilder for the class being built
1762     * @param mb The method the expression will go into
1763     *
1764     *
1765     * @exception StandardException Thrown on error
1766     */

1767
1768    public void generateResultSet(ExpressionClassBuilder acb,
1769                                           MethodBuilder mb)
1770                                    throws StandardException
1771    {
1772        System.out.println("I am a " + getClass());
1773        if (SanityManager.DEBUG)
1774            SanityManager.NOTREACHED();
1775        return;
1776    }
1777
1778
1779    /**
1780     * Get the lock mode for the target of an update statement
1781     * (a delete or update). The update mode will always be row for
1782     * CurrentOfNodes. It will be table if there is no where clause.
1783     *
1784     * @see TransactionController
1785     *
1786     * @return The lock mode
1787     */

1788    public int updateTargetLockMode()
1789    {
1790        return TransactionController.MODE_TABLE;
1791    }
1792
1793    /**
1794     * Mark this node and its children as not being a flattenable join.
1795     */

1796    void notFlattenableJoin()
1797    {
1798    }
1799
1800    /**
1801     * Return whether or not the underlying ResultSet tree
1802     * is ordered on the specified columns.
1803     * RESOLVE - This method currently only considers the outermost table
1804     * of the query block.
1805     *
1806     * @param crs The specified ColumnReference[]
1807     * @param permuteOrdering Whether or not the order of the CRs in the array can be permuted
1808     * @param fbtVector Vector that is to be filled with the FromBaseTable
1809     *
1810     * @return Whether the underlying ResultSet tree
1811     * is ordered on the specified column.
1812     *
1813     * @exception StandardException Thrown on error
1814     */

1815    boolean isOrderedOn(ColumnReference[] crs, boolean permuteOrdering, Vector JavaDoc fbtVector)
1816                throws StandardException
1817    {
1818        return false;
1819    }
1820
1821    /**
1822     * Return whether or not this ResultSet tree is guaranteed to return
1823     * at most 1 row based on heuristics. (A RowResultSetNode and a
1824     * SELECT with a non-grouped aggregate will return at most 1 row.)
1825     *
1826     * @return Whether or not this ResultSet tree is guaranteed to return
1827     * at most 1 row based on heuristics.
1828     */

1829    boolean returnsAtMostOneRow()
1830    {
1831        return false;
1832    }
1833
1834    /**
1835     * Replace any DEFAULTs with the associated tree for the default.
1836     *
1837     * @param ttd The TableDescriptor for the target table.
1838     * @param tcl The RCL for the target table.
1839     *
1840     * @exception StandardException Thrown on error
1841     */

1842    void replaceDefaults(TableDescriptor ttd, ResultColumnList tcl)
1843        throws StandardException
1844    {
1845        // Only subclasses with something to do override this.
1846
}
1847
1848    /**
1849     * Is it possible to do a distinct scan on this ResultSet tree.
1850     * (See SelectNode for the criteria.)
1851     *
1852     * @param distinctColumns the set of distinct columns
1853     * @return Whether or not it is possible to do a distinct scan on this ResultSet tree.
1854     */

1855    boolean isPossibleDistinctScan(Set distinctColumns)
1856    {
1857        return false;
1858    }
1859
1860    /**
1861     * Mark the underlying scan as a distinct scan.
1862     */

1863    void markForDistinctScan()
1864    {
1865        if (SanityManager.DEBUG)
1866        {
1867            SanityManager.THROWASSERT(
1868                "markForDistinctScan() not expected to be called for " +
1869                getClass().getName());
1870        }
1871    }
1872
1873    /**
1874     * Notify the underlying result set tree that the result is
1875     * ordering dependent. (For example, no bulk fetch on an index
1876     * if under an IndexRowToBaseRow.)
1877     */

1878    void markOrderingDependent()
1879    {
1880        if (SanityManager.DEBUG)
1881        {
1882            SanityManager.THROWASSERT(
1883                "markOrderingDependent() not expected to be called for " +
1884                getClass().getName());
1885        }
1886    }
1887
1888
1889    /**
1890     * Count the number of distinct aggregates in the list.
1891     * By 'distinct' we mean aggregates of the form:
1892     * <UL><I>SELECT MAX(DISTINCT x) FROM T<\I><\UL>
1893     *
1894     * @return number of aggregates
1895     */

1896    protected static final int numDistinctAggregates(Vector JavaDoc aggregateVector)
1897    {
1898        int count = 0;
1899        int size = aggregateVector.size();
1900
1901        for (int index = 0; index < size; index++)
1902        {
1903            count += (((AggregateNode) aggregateVector.elementAt(index)).isDistinct() == true) ?
1904                        1 : 0;
1905        }
1906        
1907        return count;
1908    }
1909
1910    // It may be we have a SELECT view underneath a LOJ.
1911
// Return null for now.. we don't do any optimization.
1912
public JBitSet LOJgetReferencedTables(int numTables)
1913                throws StandardException
1914    {
1915        if (this instanceof FromTable)
1916        {
1917            if (((FromTable)this).tableNumber != -1)
1918            {
1919                JBitSet map = new JBitSet(numTables);
1920                map.set(((FromTable)this).tableNumber);
1921                return map;
1922            }
1923        }
1924
1925        return null;
1926    }
1927    
1928}
1929
Popular Tags