KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.InsertNode
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.services.loader.GeneratedMethod;
27
28 import org.apache.derby.iapi.services.compiler.JavaFactory;
29 import org.apache.derby.iapi.services.compiler.MethodBuilder;
30
31 import org.apache.derby.iapi.reference.SQLState;
32 import org.apache.derby.iapi.error.StandardException;
33
34 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
35
36 import org.apache.derby.iapi.sql.conn.Authorizer;
37
38 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
39 import org.apache.derby.iapi.sql.compile.Visitable;
40 import org.apache.derby.iapi.sql.compile.Visitor;
41 import org.apache.derby.iapi.sql.compile.CompilerContext;
42
43 import org.apache.derby.iapi.reference.ClassName;
44
45 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
46 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
47 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
48 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
49 import org.apache.derby.iapi.sql.dictionary.IndexLister;
50 import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
51 import org.apache.derby.iapi.types.TypeId;
52
53 import org.apache.derby.iapi.sql.ResultSet;
54 import org.apache.derby.iapi.sql.Activation;
55 import org.apache.derby.iapi.sql.StatementType;
56
57 import org.apache.derby.iapi.sql.execute.ConstantAction;
58
59 import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
60 import org.apache.derby.iapi.store.access.TransactionController;
61 import org.apache.derby.iapi.types.RowLocation;
62
63 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
64 import org.apache.derby.iapi.services.compiler.MethodBuilder;
65
66 import org.apache.derby.iapi.services.sanity.SanityManager;
67
68 import org.apache.derby.vti.DeferModification;
69
70 import org.apache.derby.iapi.services.classfile.VMOpcode;
71 import org.apache.derby.iapi.util.StringUtil;
72
73 import org.apache.derby.catalog.UUID;
74
75 import org.apache.derby.impl.sql.execute.FKInfo;
76
77 import java.util.Properties JavaDoc;
78
79 import org.apache.derby.iapi.services.io.FormatableBitSet;
80 import org.apache.derby.iapi.util.ReuseFactory;
81
82 /**
83  * An InsertNode is the top node in a query tree for an
84  * insert statement.
85  * <p>
86  * After parsing, the node contains
87  * targetTableName: the target table for the insert
88  * collist: a list of column names, if specified
89  * queryexpr: the expression being inserted, either
90  * a values clause or a select form; both
91  * of these are represented via the SelectNode,
92  * potentially with a TableOperatorNode such as
93  * UnionNode above it.
94  * <p>
95  * After binding, the node has had the target table's
96  * descriptor located and inserted, and the queryexpr
97  * and collist have been massaged so that they are identical
98  * to the table layout. This involves adding any default
99  * values for missing columns, and reordering the columns
100  * to match the table's ordering of them.
101  * <p>
102  * After optimizing, ...
103  */

104 public final class InsertNode extends DMLModStatementNode
105 {
106     public ResultColumnList targetColumnList;
107     public boolean deferred;
108     public ValueNode checkConstraints;
109     public Properties JavaDoc targetProperties;
110     public FKInfo fkInfo;
111     protected boolean bulkInsert;
112     private boolean bulkInsertReplace;
113     
114     protected RowLocation[] autoincRowLocation;
115     /**
116      * Initializer for an InsertNode.
117      *
118      * @param targetName The name of the table/VTI to insert into
119      * @param insertColumns A ResultColumnList with the names of the
120      * columns to insert into. May be null if the
121      * user did not specify the columns - in this
122      * case, the binding phase will have to figure
123      * it out.
124      * @param queryExpression The query expression that will generate
125      * the rows to insert into the given table
126      * @param targetProperties The properties specified on the target table
127      */

128
129     public void init(
130             Object JavaDoc targetName,
131             Object JavaDoc insertColumns,
132             Object JavaDoc queryExpression,
133             Object JavaDoc targetProperties)
134     {
135         /* statementType gets set in super() before we've validated
136          * any properties, so we've kludged the code to get the
137          * right statementType for a bulk insert replace.
138          */

139         super.init(
140                 queryExpression,
141                 ReuseFactory.getInteger(getStatementType(
142                                                 (Properties JavaDoc) targetProperties))
143                 );
144         setTarget((QueryTreeNode) targetName);
145         targetColumnList = (ResultColumnList) insertColumns;
146         this.targetProperties = (Properties JavaDoc) targetProperties;
147
148         /* Remember that the query expression is the source to an INSERT */
149         getResultSetNode().setInsertSource();
150     }
151
152     /**
153      * Convert this object to a String. See comments in QueryTreeNode.java
154      * for how this should be done for tree printing.
155      *
156      * @return This object as a String
157      */

158
159     public String JavaDoc toString()
160     {
161         if (SanityManager.DEBUG)
162         {
163             try {
164                 return ( (targetTableName!=null) ? targetTableName : targetVTI.getTableName() ).toString() + "\n"
165                     + targetProperties + "\n"
166                     + super.toString();
167             } catch (org.apache.derby.iapi.error.StandardException e) {
168                 return "tableName: <not_known>\n"
169                     + targetProperties + "\n"
170                     + super.toString();
171             }
172         }
173         else
174         {
175             return "";
176         }
177     }
178
179     public String JavaDoc statementToString()
180     {
181         return "INSERT";
182     }
183
184     /**
185      * Prints the sub-nodes of this object. See QueryTreeNode.java for
186      * how tree printing is supposed to work.
187      *
188      * @param depth The depth of this node in the tree
189      */

190
191     public void printSubNodes(int depth)
192     {
193         if (SanityManager.DEBUG)
194         {
195             super.printSubNodes(depth);
196
197             if (targetTableName != null)
198             {
199                 printLabel(depth, "targetTableName: ");
200                 targetTableName.treePrint(depth + 1);
201             }
202
203             if (targetColumnList != null)
204             {
205                 printLabel(depth, "targetColumnList: ");
206                 targetColumnList.treePrint(depth + 1);
207             }
208
209             /* RESOLVE - need to print out targetTableDescriptor */
210         }
211     }
212
213     /**
214      * Bind this InsertNode. This means looking up tables and columns and
215      * getting their types, and figuring out the result types of all
216      * expressions, as well as doing view resolution, permissions checking,
217      * etc.
218      * <p>
219      * Binding an insert will also massage the tree so that
220      * the collist and select column order/number are the
221      * same as the layout of the table in the store.
222      *
223      * @return The bound query tree
224      *
225      * @exception StandardException Thrown on error
226      */

227
228     public QueryTreeNode bind() throws StandardException
229     {
230         // We just need select privilege on the expressions
231
getCompilerContext().pushCurrentPrivType( Authorizer.SELECT_PRIV);
232
233         FromList fromList = (FromList) getNodeFactory().getNode(
234                                     C_NodeTypes.FROM_LIST,
235                                     getNodeFactory().doJoinOrderOptimization(),
236                                     getContextManager());
237
238         /* If any underlying ResultSetNode is a SelectNode, then we
239          * need to do a full bind(), including the expressions
240          * (since the fromList may include a FromSubquery).
241          */

242         DataDictionary dataDictionary = getDataDictionary();
243         super.bindResultSetsWithTables(dataDictionary);
244
245         /*
246         ** Get the TableDescriptor for the table we are inserting into
247         */

248         verifyTargetTable();
249
250         // Check the validity of the targetProperties, if they exist
251
if (targetProperties != null)
252         {
253             verifyTargetProperties(dataDictionary);
254         }
255
256         /*
257         ** Get the resultColumnList representing the columns in the base
258         ** table or VTI.
259         */

260         getResultColumnList();
261
262         /* If we have a target column list, then it must have the same # of
263          * entries as the result set's RCL.
264          */

265         if (targetColumnList != null)
266         {
267             /*
268              * Normalize synonym qualifers for column references.
269              */

270             if (synonymTableName != null)
271             {
272                 normalizeSynonymColumns ( targetColumnList, targetTableName );
273             }
274             
275             /* Bind the target column list */
276             getCompilerContext().pushCurrentPrivType( getPrivType());
277             if (targetTableDescriptor != null)
278             {
279                 targetColumnList.bindResultColumnsByName(targetTableDescriptor,
280                                                         (DMLStatementNode) this);
281             }
282             else
283             {
284                 targetColumnList.bindResultColumnsByName(targetVTI.getResultColumns(), targetVTI,
285                                                         this);
286             }
287             getCompilerContext().popCurrentPrivType();
288         }
289
290         /* Verify that all underlying ResultSets reclaimed their FromList */
291         if (SanityManager.DEBUG)
292         {
293             SanityManager.ASSERT(fromList.size() == 0,
294                 "fromList.size() is expected to be 0, not " +
295                 fromList.size() +
296                 " on return from RS.bindExpressions()");
297         }
298
299         /* Replace any DEFAULTs with the associated tree */
300         resultSet.replaceDefaults(targetTableDescriptor, targetColumnList);
301
302         /* Bind the expressions now that the result columns are bound
303          * NOTE: This will be the 2nd time for those underlying ResultSets
304          * that have tables (no harm done), but it is necessary for those
305          * that do not have tables. It's too hard/not work the effort to
306          * avoid the redundancy.
307          */

308         super.bindExpressions();
309
310         /*
311         ** If the result set is a union, it could be a table constructor.
312         ** Bind any nulls in the result columns of the table constructor
313         ** to the types of the table being inserted into.
314         **
315         ** The types of ? parameters in row constructors and table constructors
316         ** in an INSERT statement come from the result columns.
317         **
318         ** If there is a target column list, use that instead of the result
319         ** columns for the whole table, since the columns in the result set
320         ** correspond to the target column list.
321         */

322         if (targetColumnList != null)
323         {
324             if (resultSet.getResultColumns().size() > targetColumnList.size())
325                 throw StandardException.newException(SQLState.LANG_DB2_INVALID_COLS_SPECIFIED);
326             resultSet.bindUntypedNullsToResultColumns(targetColumnList);
327             resultSet.setTableConstructorTypes(targetColumnList);
328         }
329         else
330         {
331             if (resultSet.getResultColumns().size() > resultColumnList.size())
332                 throw StandardException.newException(SQLState.LANG_DB2_INVALID_COLS_SPECIFIED);
333             resultSet.bindUntypedNullsToResultColumns(resultColumnList);
334             resultSet.setTableConstructorTypes(resultColumnList);
335         }
336
337         /* Bind the columns of the result set to their expressions */
338         resultSet.bindResultColumns(fromList);
339
340         int resCols = resultSet.getResultColumns().size();
341         DataDictionary dd = getDataDictionary();
342         if (targetColumnList != null)
343         {
344             if (targetColumnList.size() != resCols)
345                 throw StandardException.newException(SQLState.LANG_DB2_INVALID_COLS_SPECIFIED);
346         }
347         else
348         {
349             if (targetTableDescriptor != null &&
350                         targetTableDescriptor.getNumberOfColumns() != resCols)
351                 throw StandardException.newException(SQLState.LANG_DB2_INVALID_COLS_SPECIFIED);
352         }
353
354         /* See if the ResultSet's RCL needs to be ordered to match the target
355          * list, or "enhanced" to accommodate defaults. It can only need to
356          * be ordered if there is a target column list. It needs to be
357          * enhanced if there are fewer source columns than there are columns
358          * in the table.
359          */

360         boolean inOrder = true;
361         int numTableColumns = resultColumnList.size();
362
363         /* colMap[] will be the size of the target list, which could be larger
364          * than the current size of the source list. In that case, the source
365          * list will be "enhanced" to include defaults.
366          */

367         int[] colMap = new int[numTableColumns];
368
369         // set the fields to an unused value
370
for (int i = 0; i < colMap.length; i++)
371         {
372             colMap[i] = -1;
373         }
374
375         /* Create the source/target list mapping */
376         if (targetColumnList != null)
377         {
378             /*
379             ** There is a target column list, so the result columns might
380             ** need to be ordered. Step through the target column list
381             ** and remember the position in the target table of each column.
382             ** Remember if any of the columns are out of order.
383             */

384             int targetSize = targetColumnList.size();
385             for (int index = 0; index < targetSize; index++)
386             {
387                 int position =
388                     ((ResultColumn) (targetColumnList.elementAt(index))).
389                                                 columnDescriptor.getPosition();
390
391                 if (index != position-1)
392                 {
393                     inOrder = false;
394                 }
395
396                 // position is 1-base; colMap indexes and entries are 0-based.
397
colMap[position-1] = index;
398             }
399         }
400         else
401         {
402             /*
403             ** There is no target column list, so the result columns in the
404             ** source are presumed to be in the same order as the target
405             ** table.
406             */

407             for (int position = 0;
408                 position < resultSet.getResultColumns().size();
409                 position++)
410             {
411                 colMap[position] = position;
412             }
413         }
414
415         // colmap[x] == y means that column x in the target table
416
// maps to column y in the source result set.
417
// colmap[x] == -1 means that column x in the target table
418
// maps to its default value.
419
// both colmap indexes and values are 0-based.
420

421         /* if the list is in order and complete, we don't have to change
422          * the tree. If it is not, then we call RSN.enhanceRCLForInsert()
423          * which will either
424          * (reorder and/or "enhance" the source RCL within the same RSN) or
425          * (generate and return a PRN with a new reordered/enhanced RCL above
426          * the existing RSN). This way, RSN's that understand how to do projections
427          * can avoid the additional PRN while those that do not will get one.
428          */

429         /* NOTE - javascope gives confusing branch coverage info here. By
430          * breaking apart the following if condition, I have verified that
431          * we test all cases. (Jerry 7/17/97)
432          */

433         if (! inOrder || resultSet.resultColumns.size() < numTableColumns)
434         {
435             // one thing we do know is that all of the resultsets underneath
436
// us have their resultColumn names filled in with the names of
437
// the target table columns. That makes generating the mapping
438
// "easier" -- we simply generate the names of the target table columns
439
// that are included. For the missing columns, we generate default
440
// value expressions.
441

442             resultSet = resultSet.enhanceRCLForInsert(numTableColumns, colMap,
443                                                       dataDictionary,
444                                                       targetTableDescriptor, targetVTI);
445         }
446
447         if (resultSet instanceof UnionNode)
448         {
449             // If we are inserting a number of rows in VALUES clause, we need to
450
// examine each row for 'autoincrement'.
451
resultColumnList.checkAutoincrementUnion(resultSet);
452         }
453         else resultColumnList.checkAutoincrement(resultSet.getResultColumns());
454         resultColumnList.checkStorableExpressions(resultSet.getResultColumns());
455         /* Insert a NormalizeResultSetNode above the source if the source
456          * and target column types and lengths do not match.
457          */

458         if (! resultColumnList.columnTypesAndLengthsMatch(
459                                                 resultSet.getResultColumns()))
460         {
461             resultSet = resultSet.genNormalizeResultSetNode(resultSet, false);
462             resultColumnList.copyTypesAndLengthsToSource(resultSet.getResultColumns());
463         }
464
465         if (targetTableDescriptor != null)
466         {
467             /* Get and bind all constraints on the table */
468             ResultColumnList sourceRCL = resultSet.getResultColumns();
469             sourceRCL.copyResultColumnNames(resultColumnList);
470             checkConstraints = bindConstraints(dataDictionary,
471                                                 getNodeFactory(),
472                                                 targetTableDescriptor,
473                                                 null,
474                                                 sourceRCL,
475                                                 (int[]) null,
476                                                 (FormatableBitSet) null,
477                                                 false,
478                                                 true); /* we always include
479                                                          * triggers in core language */

480     
481             /* Do we need to do a deferred mode insert */
482             /*
483             ** Deferred if:
484             ** If the target table is also a source table
485             ** Self-referencing foreign key constraint
486             ** trigger
487             */

488             if (resultSet.referencesTarget(
489                                     targetTableDescriptor.getName(), true) ||
490                  requiresDeferredProcessing())
491             {
492                 deferred = true;
493
494                 /* Disallow bulk insert replace when target table
495                  * is also a source table.
496                  */

497                 if (bulkInsertReplace &&
498                     resultSet.referencesTarget(
499                                     targetTableDescriptor.getName(), true))
500                 {
501                     throw StandardException.newException(SQLState.LANG_INVALID_BULK_INSERT_REPLACE,
502                                     targetTableDescriptor.getQualifiedName());
503                 }
504             }
505
506             /* Get the list of indexes on the table being inserted into */
507             getAffectedIndexes(targetTableDescriptor);
508             TransactionController tc =
509                 getLanguageConnectionContext().getTransactionCompile();
510
511             autoincRowLocation =
512                 dd.computeAutoincRowLocations(tc, targetTableDescriptor);
513
514             if (isPrivilegeCollectionRequired())
515             {
516                 getCompilerContext().pushCurrentPrivType(getPrivType());
517                 getCompilerContext().addRequiredTablePriv(targetTableDescriptor);
518                 getCompilerContext().popCurrentPrivType();
519             }
520
521         }
522         else
523         {
524             deferred = VTIDeferModPolicy.deferIt( DeferModification.INSERT_STATEMENT,
525                                                   targetVTI,
526                                                   null,
527                                                   resultSet);
528         }
529         
530         getCompilerContext().popCurrentPrivType();
531         return this;
532     }
533
534     int getPrivType()
535     {
536         return Authorizer.INSERT_PRIV;
537     }
538
539     /**
540      * Return true if the node references SESSION schema tables (temporary or permanent)
541      *
542      * @return true if references SESSION schema tables, else false
543      *
544      * @exception StandardException Thrown on error
545      */

546     public boolean referencesSessionSchema()
547         throws StandardException
548     {
549         boolean returnValue = false;
550
551         //If this node references a SESSION schema table, then return true.
552
if (targetTableDescriptor != null)
553             returnValue = isSessionSchema(targetTableDescriptor.getSchemaDescriptor());
554
555         if (returnValue == false)
556             returnValue = resultSet.referencesSessionSchema();
557
558         return returnValue;
559     }
560
561     /**
562      * Verify that the target properties that we are interested in
563      * all hold valid values.
564      * NOTE: Any target property which is valid but cannot be supported
565      * due to a target database, etc. will be turned off quietly.
566      *
567      * @param dd The DataDictionary
568      *
569      * @exception StandardException Thrown on error
570      */

571     private void verifyTargetProperties(DataDictionary dd)
572         throws StandardException
573     {
574         // The only property that we're currently interested in is insertMode
575
String JavaDoc insertMode = targetProperties.getProperty("insertMode");
576         if (insertMode != null)
577         {
578             String JavaDoc upperValue = StringUtil.SQLToUpperCase(insertMode);
579             if (! upperValue.equals("BULKINSERT") &&
580                 ! upperValue.equals("REPLACE"))
581             {
582                 throw StandardException.newException(SQLState.LANG_INVALID_INSERT_MODE,
583                                 insertMode,
584                                 targetTableName);
585             }
586             else
587             {
588                 /* Turn off bulkInsert if it is on and we can't support it. */
589                 if (! verifyBulkInsert(dd, upperValue))
590                 {
591                     targetProperties.remove("insertMode");
592                 }
593                 else
594                 {
595                     /* Now we know we're doing bulk insert */
596                     bulkInsert = true;
597
598                     if (upperValue.equals("REPLACE"))
599                     {
600                         bulkInsertReplace = true;
601                     }
602
603                     // Validate the bulkFetch property if specified
604
String JavaDoc bulkFetchStr = targetProperties.getProperty("bulkFetch");
605                     if (bulkFetchStr != null)
606                     {
607                         int bulkFetch = getIntProperty(bulkFetchStr, "bulkFetch");
608
609                         // verify that the specified value is valid
610
if (bulkFetch <= 0)
611                         {
612                             throw StandardException.newException(SQLState.LANG_INVALID_BULK_FETCH_VALUE,
613                                     String.valueOf(bulkFetch));
614                         }
615                     }
616                 }
617             }
618         }
619     }
620
621     /**
622      * Do the bind time checks to see if bulkInsert is allowed on
623      * this table. bulkInsert is disallowed at bind time for:
624      * o target databases
625      * o (tables with triggers?)
626      * (It is disallowed at execution time if the table has at
627      * least 1 row in it or if it is a deferred mode insert.)
628      *
629      * @param dd The DataDictionary
630      * @param mode The insert mode
631      *
632      * @return Whether or not bulkInsert is allowed.
633      *
634      * @exception StandardException Thrown on error
635      */

636     private boolean verifyBulkInsert(DataDictionary dd, String JavaDoc mode)
637         throws StandardException
638     {
639         return true;
640     }
641
642     /**
643      * Compile constants that Execution will use
644      *
645      * @exception StandardException Thrown on failure
646      */

647     public ConstantAction makeConstantAction() throws StandardException
648     {
649
650         /* Different constant actions for base tables and updatable VTIs */
651         if (targetTableDescriptor != null)
652         {
653             // Base table
654

655             long heapConglomId = targetTableDescriptor.getHeapConglomerateId();
656             TransactionController tc =
657                 getLanguageConnectionContext().getTransactionCompile();
658             int numIndexes = (targetTableDescriptor != null) ?
659                                 indexConglomerateNumbers.length : 0;
660             StaticCompiledOpenConglomInfo[] indexSCOCIs =
661                 new StaticCompiledOpenConglomInfo[numIndexes];
662
663             for (int index = 0; index < numIndexes; index++)
664             {
665                 indexSCOCIs[index] = tc.getStaticCompiledConglomInfo(indexConglomerateNumbers[index]);
666             }
667
668             /*
669             ** If we're doing bulk insert, do table locking regardless of
670             ** what the optimizer decided. This is because bulk insert is
671             ** generally done with a large number of rows into an empty table.
672             ** We also do table locking if the table's lock granularity is
673             ** set to table.
674             */

675             if (bulkInsert ||
676                 targetTableDescriptor.getLockGranularity() == TableDescriptor.TABLE_LOCK_GRANULARITY)
677             {
678                 lockMode = TransactionController.MODE_TABLE;
679             }
680
681             return getGenericConstantActionFactory().getInsertConstantAction
682                 ( targetTableDescriptor,
683                   heapConglomId,
684                   tc.getStaticCompiledConglomInfo(heapConglomId),
685                   indicesToMaintain,
686                   indexConglomerateNumbers,
687                   indexSCOCIs,
688                   indexNames,
689                   deferred,
690                   false,
691                   targetTableDescriptor.getUUID(),
692                   lockMode,
693                   null, null,
694                   targetProperties,
695                   getFKInfo(),
696                   getTriggerInfo(),
697                   resultColumnList.getStreamStorableColIds(targetTableDescriptor.getNumberOfColumns()),
698                   getIndexedCols(),
699                   (UUID) null,
700                   null,
701                   null,
702                   resultSet.isOneRowResultSet(),
703                   autoincRowLocation
704                   );
705         }
706         else
707         {
708             /* Return constant action for VTI
709              * NOTE: ConstantAction responsible for preserving instantiated
710              * VTIs for in-memory queries and for only preserving VTIs
711              * that implement Serializable for SPSs.
712              */

713             return getGenericConstantActionFactory().getUpdatableVTIConstantAction( DeferModification.INSERT_STATEMENT,
714                         deferred);
715         }
716     }
717
718     /**
719      * Create a boolean[] to track the (0-based) columns which are indexed.
720      *
721      * @return A boolean[] to track the (0-based) columns which are indexed.
722      *
723      * @exception StandardException Thrown on failure
724      */

725     public boolean[] getIndexedCols() throws StandardException
726     {
727         /* Create a boolean[] to track the (0-based) columns which are indexed */
728         boolean[] indexedCols = new boolean[targetTableDescriptor.getNumberOfColumns()];
729         for (int index = 0; index < indicesToMaintain.length; index++)
730         {
731             int[] colIds = indicesToMaintain[index].getIndexDescriptor().baseColumnPositions();
732
733             for (int index2 = 0; index2 < colIds.length; index2++)
734             {
735                 indexedCols[colIds[index2] - 1] = true;
736             }
737         }
738
739         return indexedCols;
740     }
741
742     /**
743      * Code generation for insert
744      * creates an expression for:
745      * ResultSetFactory.getInsertResultSet(resultSet.generate(ps), this )
746      *
747      * @param acb The ActivationClassBuilder for the class being built
748      * @param mb the method for the execute() method to be built
749      *
750      * @exception StandardException Thrown on error
751      */

752     public void generate(ActivationClassBuilder acb,
753                                 MethodBuilder mb)
754                             throws StandardException
755     {
756         //If the DML is on the temporary table, generate the code to mark temporary table as modified in the current UOW
757
generateCodeForTemporaryTable(acb, mb);
758
759         /* generate the parameters */
760         generateParameterValueSet(acb);
761         // Base table
762
if (targetTableDescriptor != null)
763         {
764             /*
765             ** Generate the insert result set, giving it either the original
766             ** source or the normalize result set, the constant action,
767             ** and "this".
768             */

769
770             acb.pushGetResultSetFactoryExpression(mb);
771
772             // arg 1
773
resultSet.generate(acb, mb);
774
775             // arg 2 generate code to evaluate CHECK CONSTRAINTS
776
generateCheckConstraints( checkConstraints, acb, mb );
777
778             mb.callMethod(VMOpcode.INVOKEINTERFACE, (String JavaDoc) null, "getInsertResultSet", ClassName.ResultSet, 2);
779         }
780         else
781         {
782             /* Generate code for the VTI
783              * NOTE: we need to create a dummy cost estimate for the
784              * targetVTI since we never optimized it.
785              * RESOLVEVTI - we will have to optimize it in order to
786              * push predicates into the VTI.
787              */

788             targetVTI.assignCostEstimate(resultSet.getNewCostEstimate());
789
790             /*
791             ** Generate the insert VTI result set, giving it either the original
792             ** source or the normalize result set, the constant action,
793             */

794             acb.pushGetResultSetFactoryExpression(mb);
795
796             // arg 1
797
resultSet.generate(acb, mb);
798
799             // arg 2
800
targetVTI.generate(acb, mb);
801
802             mb.callMethod(VMOpcode.INVOKEINTERFACE, (String JavaDoc) null, "getInsertVTIResultSet", ClassName.ResultSet, 2);
803         }
804     }
805
806     /**
807      * Return the type of statement, something from
808      * StatementType.
809      *
810      * @return the type of statement
811      */

812     protected final int getStatementType()
813     {
814         return StatementType.INSERT;
815     }
816
817     /**
818      * Return the statement type, where it is dependent on
819      * the targetProperties. (insertMode = replace causes
820      * statement type to be BULK_INSERT_REPLACE.
821      *
822      * @return the type of statement
823      */

824     static final int getStatementType(Properties JavaDoc targetProperties)
825     {
826         int retval = StatementType.INSERT;
827
828         // The only property that we're currently interested in is insertMode
829
String JavaDoc insertMode = (targetProperties == null) ? null : targetProperties.getProperty("insertMode");
830         if (insertMode != null)
831         {
832             String JavaDoc upperValue = StringUtil.SQLToUpperCase(insertMode);
833             if (upperValue.equals("REPLACE"))
834             {
835                 retval = StatementType.BULK_INSERT_REPLACE;
836             }
837         }
838         return retval;
839     }
840
841     /**
842      * Get the list of indexes on the table being inserted into. This
843      * is used by INSERT. This is an optimized version of what
844      * UPDATE and DELETE use.
845      *
846      * @param td TableDescriptor for the table being inserted into
847      * or deleted from
848      *
849      * @exception StandardException Thrown on error
850      */

851     private void getAffectedIndexes
852     (
853         TableDescriptor td
854     )
855                     throws StandardException
856     {
857         IndexLister indexLister = td.getIndexLister( );
858
859         indicesToMaintain = indexLister.getDistinctIndexRowGenerators();
860         indexConglomerateNumbers = indexLister.getDistinctIndexConglomerateNumbers();
861         indexNames = indexLister.getDistinctIndexNames();
862
863         /* Add dependencies on all indexes in the list */
864         ConglomerateDescriptor[] cds = td.getConglomerateDescriptors();
865         CompilerContext cc = getCompilerContext();
866
867         for (int index = 0; index < cds.length; index++)
868         {
869             cc.createDependency(cds[index]);
870         }
871     }
872     
873 } // end of class InsertNode
874
Popular Tags