KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.DMLStatementNode
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.Visitable;
29 import org.apache.derby.iapi.sql.compile.Visitor;
30 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
31
32 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
33 import org.apache.derby.iapi.sql.conn.Authorizer;
34 import org.apache.derby.iapi.sql.execute.ExecutionContext;
35 import org.apache.derby.iapi.sql.ResultColumnDescriptor;
36 import org.apache.derby.iapi.sql.ParameterValueSet;
37 import org.apache.derby.iapi.sql.ResultDescription;
38
39 import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
40 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
41 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
42 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
43 import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
44
45 import org.apache.derby.iapi.services.monitor.Monitor;
46
47 import org.apache.derby.iapi.services.compiler.MethodBuilder;
48
49 import org.apache.derby.iapi.services.sanity.SanityManager;
50
51 import org.apache.derby.iapi.util.JBitSet;
52
53 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
54
55 import java.util.Enumeration JavaDoc;
56 import java.util.Properties JavaDoc;
57 import java.util.Vector JavaDoc;
58
59 /**
60  * A DMLStatementNode represents any type of DML statement: a cursor declaration,
61  * an INSERT statement, and UPDATE statement, or a DELETE statement. All DML
62  * statements have result sets, but they do different things with them. A
63  * SELECT statement sends its result set to the client, an INSERT statement
64  * inserts its result set into a table, a DELETE statement deletes from a
65  * table the rows corresponding to the rows in its result set, and an UPDATE
66  * statement updates the rows in a base table corresponding to the rows in its
67  * result set.
68  *
69  * @author Jeff Lichtman
70  */

71
72 abstract class DMLStatementNode extends StatementNode
73 {
74
75     /**
76      * The result set is the rows that result from running the
77      * statement. What this means for SELECT statements is fairly obvious.
78      * For a DELETE, there is one result column representing the
79      * key of the row to be deleted (most likely, the location of the
80      * row in the underlying heap). For an UPDATE, the row consists of
81      * the key of the row to be updated plus the updated columns. For
82      * an INSERT, the row consists of the new column values to be
83      * inserted, with no key (the system generates a key).
84      *
85      * The parser doesn't know anything about keys, so the columns
86      * representing the keys will be added after parsing (perhaps in
87      * the binding phase?).
88      *
89      */

90     ResultSetNode resultSet;
91
92     /**
93      * Initializer for a DMLStatementNode
94      *
95      * @param resultSet A ResultSetNode for the result set of the
96      * DML statement
97      */

98
99     public void init(Object JavaDoc resultSet)
100     {
101         this.resultSet = (ResultSetNode) resultSet;
102     }
103
104     /**
105      * Prints the sub-nodes of this object. See QueryTreeNode.java for
106      * how tree printing is supposed to work.
107      *
108      * @param depth The depth of this node in the tree
109      */

110
111     public void printSubNodes(int depth)
112     {
113         if (SanityManager.DEBUG)
114         {
115             super.printSubNodes(depth);
116             if (resultSet != null)
117             {
118                 printLabel(depth, "resultSet: ");
119                 resultSet.treePrint(depth + 1);
120             }
121         }
122     }
123
124     /**
125      * Get the ResultSetNode from this DML Statement.
126      * (Useful for view resolution after parsing the view definition.)
127      *
128      * @return ResultSetNode The ResultSetNode from this DMLStatementNode.
129      */

130     public ResultSetNode getResultSetNode()
131     {
132         return resultSet;
133     }
134
135     /**
136      * Bind this DMLStatementNode. This means looking up tables and columns and
137      * getting their types, and figuring out the result types of all
138      * expressions, as well as doing view resolution, permissions checking,
139      * etc.
140      *
141      * @param dataDictionary The DataDictionary to use to look up
142      * columns, tables, etc.
143      *
144      * @return The bound query tree
145      *
146      * @exception StandardException Thrown on error
147      */

148
149     public QueryTreeNode bind(DataDictionary dataDictionary)
150                      throws StandardException
151     {
152         // We just need select privilege on most columns and tables
153
getCompilerContext().pushCurrentPrivType(getPrivType());
154         try {
155             /*
156             ** Bind the tables before binding the expressions, so we can
157             ** use the results of table binding to look up columns.
158             */

159             bindTables(dataDictionary);
160
161             /* Bind the expressions */
162             bindExpressions();
163         }
164         finally
165         {
166             getCompilerContext().popCurrentPrivType();
167         }
168
169         return this;
170     }
171
172     /**
173      * Bind only the underlying ResultSets with tables. This is necessary for
174      * INSERT, where the binding order depends on the underlying ResultSets.
175      * This means looking up tables and columns and
176      * getting their types, and figuring out the result types of all
177      * expressions, as well as doing view resolution, permissions checking,
178      * etc.
179      *
180      * @param dataDictionary The DataDictionary to use to look up
181      * columns, tables, etc.
182      *
183      * @return The bound query tree
184      *
185      * @exception StandardException Thrown on error
186      */

187
188     public QueryTreeNode bindResultSetsWithTables(DataDictionary dataDictionary)
189                      throws StandardException
190     {
191         /* Okay to bindly bind the tables, since ResultSets without tables
192          * know to handle the call.
193          */

194         bindTables(dataDictionary);
195
196         /* Bind the expressions in the underlying ResultSets with tables */
197         bindExpressionsWithTables();
198
199         return this;
200     }
201
202     /**
203      * Bind the tables in this DML statement.
204      *
205      * @param dataDictionary The data dictionary to use to look up the tables
206      *
207      * @exception StandardException Thrown on error
208      */

209
210     protected void bindTables(DataDictionary dataDictionary)
211             throws StandardException
212     {
213         /* Bind the tables in the resultSet
214          * (DMLStatementNode is above all ResultSetNodes, so table numbering
215          * will begin at 0.)
216          * In case of referential action on delete , the table numbers can be
217          * > 0 because the nodes are create for dependent tables also in the
218          * the same context.
219          */

220
221         resultSet = resultSet.bindNonVTITables(
222                         dataDictionary,
223                         (FromList) getNodeFactory().getNode(
224                             C_NodeTypes.FROM_LIST,
225                             getNodeFactory().doJoinOrderOptimization(),
226                             getContextManager()));
227         resultSet = resultSet.bindVTITables(
228                         (FromList) getNodeFactory().getNode(
229                             C_NodeTypes.FROM_LIST,
230                             getNodeFactory().doJoinOrderOptimization(),
231                             getContextManager()));
232     }
233
234     /**
235      * Bind the expressions in this DML statement.
236      *
237      * @exception StandardException Thrown on error
238      */

239
240     protected void bindExpressions()
241             throws StandardException
242     {
243         FromList fromList = (FromList) getNodeFactory().getNode(
244                                 C_NodeTypes.FROM_LIST,
245                                 getNodeFactory().doJoinOrderOptimization(),
246                                 getContextManager());
247
248         /* Bind the expressions under the resultSet */
249         resultSet.bindExpressions(fromList);
250
251         /* Verify that all underlying ResultSets reclaimed their FromList */
252         if (SanityManager.DEBUG)
253         SanityManager.ASSERT(fromList.size() == 0,
254             "fromList.size() is expected to be 0, not " + fromList.size() +
255             " on return from RS.bindExpressions()");
256     }
257
258     /**
259      * Bind the expressions in the underlying ResultSets with tables.
260      *
261      * @exception StandardException Thrown on error
262      */

263
264     protected void bindExpressionsWithTables()
265             throws StandardException
266     {
267         FromList fromList = (FromList) getNodeFactory().getNode(
268                                 C_NodeTypes.FROM_LIST,
269                                 getNodeFactory().doJoinOrderOptimization(),
270                                 getContextManager());
271
272         /* Bind the expressions under the resultSet */
273         resultSet.bindExpressionsWithTables(fromList);
274
275         /* Verify that all underlying ResultSets reclaimed their FromList */
276         if (SanityManager.DEBUG)
277         SanityManager.ASSERT(fromList.size() == 0,
278             "fromList.size() is expected to be 0, not " + fromList.size() +
279             " on return from RS.bindExpressions()");
280     }
281
282     /**
283      * Returns the type of activation this class
284      * generates.
285      *
286      * @return either (NEED_ROW_ACTIVATION | NEED_PARAM_ACTIVATION) or
287      * (NEED_ROW_ACTIVATION) depending on params
288      *
289      */

290     int activationKind()
291     {
292         Vector JavaDoc parameterList = getCompilerContext().getParameterList();
293         /*
294         ** We need rows for all types of DML activations. We need parameters
295         ** only for those that have parameters.
296         */

297         if (parameterList != null && parameterList.size() > 0)
298         {
299             return StatementNode.NEED_PARAM_ACTIVATION;
300         }
301         else
302         {
303             return StatementNode.NEED_ROW_ACTIVATION;
304         }
305     }
306
307     /**
308      * Optimize a DML statement (which is the only type of statement that
309      * should need optimizing, I think). This method over-rides the one
310      * in QueryTreeNode.
311      *
312      * This method takes a bound tree, and returns an optimized tree.
313      * It annotates the bound tree rather than creating an entirely
314      * new tree.
315      *
316      * Throws an exception if the tree is not bound, or if the binding
317      * is out of date.
318      *
319      * @return An optimized QueryTree
320      *
321      * @exception StandardException Thrown on error
322      */

323
324     public QueryTreeNode optimize() throws StandardException
325     {
326         resultSet = resultSet.preprocess(getCompilerContext().getNumTables(),
327                                          null,
328                                          (FromList) null);
329         resultSet = resultSet.optimize(getDataDictionary(), null, 1.0d);
330
331         resultSet = resultSet.modifyAccessPaths();
332
333         /* If this is a cursor, then we
334          * need to generate a new ResultSetNode to enable the scrolling
335          * on top of the tree before modifying the access paths.
336          */

337         if (this instanceof CursorNode)
338         {
339             ResultColumnList siRCList;
340             ResultColumnList childRCList;
341             ResultSetNode siChild = resultSet;
342
343             /* We get a shallow copy of the ResultColumnList and its
344              * ResultColumns. (Copy maintains ResultColumn.expression for now.)
345              */

346             siRCList = resultSet.getResultColumns();
347             childRCList = siRCList.copyListAndObjects();
348             resultSet.setResultColumns(childRCList);
349
350             /* Replace ResultColumn.expression with new VirtualColumnNodes
351              * in the ScrollInsensitiveResultSetNode's ResultColumnList. (VirtualColumnNodes include
352              * pointers to source ResultSetNode, this, and source ResultColumn.)
353              */

354             siRCList.genVirtualColumnNodes(resultSet, childRCList);
355
356             /* Finally, we create the new ScrollInsensitiveResultSetNode */
357             resultSet = (ResultSetNode) getNodeFactory().
358                             getNode(
359                                 C_NodeTypes.SCROLL_INSENSITIVE_RESULT_SET_NODE,
360                                 resultSet,
361                                 siRCList,
362                                 null,
363                                 getContextManager());
364             // Propagate the referenced table map if it's already been created
365
if (siChild.getReferencedTableMap() != null)
366             {
367                 resultSet.setReferencedTableMap((JBitSet) siChild.getReferencedTableMap().clone());
368             }
369         }
370
371         return this;
372     }
373
374     /**
375      * Make a ResultDescription for use in a PreparedStatement.
376      *
377      * ResultDescriptions are visible to JDBC only for cursor statements.
378      * For other types of statements, they are only used internally to
379      * get descriptions of the base tables being affected. For example,
380      * for an INSERT statement, the ResultDescription describes the
381      * rows in the table being inserted into, which is useful when
382      * the values being inserted are of a different type or length
383      * than the columns in the base table.
384      *
385      * @return A ResultDescription for this DML statement
386      */

387
388     public ResultDescription makeResultDescription()
389     {
390         ExecutionContext ec = (ExecutionContext) getContextManager().getContext(
391             ExecutionContext.CONTEXT_ID);
392         ResultColumnDescriptor[] colDescs = resultSet.makeResultDescriptors(ec);
393         String JavaDoc statementType = statementToString();
394
395         return ec.getExecutionFactory().getResultDescription(colDescs, statementType );
396     }
397
398     /**
399      * Generate the code to create the ParameterValueSet, if necessary,
400      * when constructing the activation. Also generate the code to call
401      * a method that will throw an exception if we try to execute without
402      * all the parameters being set.
403      *
404      * @param acb The ActivationClassBuilder for the class we're building
405      */

406
407     void generateParameterValueSet(ActivationClassBuilder acb)
408         throws StandardException
409     {
410         Vector JavaDoc parameterList = getCompilerContext().getParameterList();
411         int numberOfParameters = (parameterList == null) ? 0 : parameterList.size();
412
413         if (numberOfParameters <= 0)
414             return;
415
416             ParameterNode.generateParameterValueSet
417                 ( acb, numberOfParameters, parameterList);
418     }
419
420     /**
421      * A read statement is atomic (DMLMod overrides us) if there
422      * are no work units, and no SELECT nodes, or if its SELECT nodes
423      * are all arguments to a function. This is admittedly
424      * a bit simplistic, what if someone has: <pre>
425      * VALUES myfunc(SELECT max(c.commitFunc()) FROM T)
426      * </pre>
427      * but we aren't going too far out of our way to
428      * catch every possible wierd case. We basically
429      * want to be permissive w/o allowing someone to partially
430      * commit a write.
431      *
432      * @return true if the statement is atomic
433      *
434      * @exception StandardException on error
435      */

436     public boolean isAtomic() throws StandardException
437     {
438         /*
439         ** If we have a FromBaseTable then we have
440         ** a SELECT, so we want to consider ourselves
441         ** atomic. Don't drill below StaticMethodCallNodes
442         ** to allow a SELECT in an argument to a method
443         ** call that can be atomic.
444         */

445         HasNodeVisitor visitor = new HasNodeVisitor(FromBaseTable.class, StaticMethodCallNode.class);
446                                                     
447         this.accept(visitor);
448         if (visitor.hasNode())
449         {
450             return true;
451         }
452
453         return false;
454     }
455
456     /**
457      * Accept a visitor, and call v.visit()
458      * on child nodes as necessary.
459      *
460      * @param v the visitor
461      *
462      * @exception StandardException on error
463      */

464     public Visitable accept(Visitor v)
465         throws StandardException
466     {
467         if (v.skipChildren(this))
468         {
469             return v.visit(this);
470         }
471
472         if (resultSet != null && !v.stopTraversal())
473         {
474             resultSet = (ResultSetNode)resultSet.accept(v);
475         }
476
477         return this;
478     }
479
480     /**
481      * Return default privilege needed for this node. Other DML nodes can override
482      * this method to set their own default privilege.
483      *
484      * @return true if the statement is atomic
485      */

486     int getPrivType()
487     {
488         return Authorizer.SELECT_PRIV;
489     }
490 }
491
Popular Tags