KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.StatementNode
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
28 import org.apache.derby.iapi.sql.compile.CompilerContext;
29
30 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
31 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
32 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
33 import org.apache.derby.iapi.store.access.ConglomerateController;
34 import org.apache.derby.iapi.store.access.TransactionController;
35
36 import org.apache.derby.iapi.services.compiler.MethodBuilder;
37
38 import org.apache.derby.iapi.reference.SQLState;
39 import org.apache.derby.iapi.reference.ClassName;
40 import org.apache.derby.iapi.services.loader.GeneratedClass;
41
42 import org.apache.derby.iapi.util.ByteArray;
43 import org.apache.derby.iapi.services.classfile.VMOpcode;
44
45 import org.apache.derby.iapi.services.sanity.SanityManager;
46
47 import java.lang.reflect.Modifier JavaDoc;
48
49 /**
50  * A StatementNode represents a single statement in the language. It is
51  * the top node for any statement.
52  * <p>
53  * StatementNode controls the class generation for query tree nodes.
54  *
55  * @author Jeff Lichtman
56  */

57
58 /*
59 * History:
60 * 5/8/97 Rick Hilleags Moved node-name-string to child classes.
61 */

62
63 abstract class StatementNode extends QueryTreeNode
64 {
65
66     /**
67      * By default, assume StatementNodes are atomic.
68      * The rare statements that aren't atomic (e.g.
69      * CALL method()) override this.
70      *
71      * @return true if the statement is atomic
72      *
73      * @exception StandardException Thrown on error
74      */

75     public boolean isAtomic() throws StandardException
76     {
77         return true;
78     }
79
80     /**
81      * Convert this object to a String. See comments in QueryTreeNode.java
82      * for how this should be done for tree printing.
83      *
84      * @return This object as a String
85      */

86
87     public String JavaDoc toString()
88     {
89         if (SanityManager.DEBUG)
90         {
91             return "statementType: " + statementToString() + "\n" +
92                 super.toString();
93         }
94         else
95         {
96             return "";
97         }
98     }
99
100     public abstract String JavaDoc statementToString();
101
102     /**
103      * create the outer shell class builder for the class we will
104      * be generating, generate the expression to stuff in it,
105      * and turn it into a class.
106      */

107     static final int NEED_DDL_ACTIVATION = 5;
108     static final int NEED_CURSOR_ACTIVATION = 4;
109     static final int NEED_PARAM_ACTIVATION = 2;
110     static final int NEED_ROW_ACTIVATION = 1;
111     static final int NEED_NOTHING_ACTIVATION = 0;
112
113     abstract int activationKind();
114
115     /* We need to get some kind of table lock (IX here) at the beginning of
116      * compilation of DMLModStatementNode and DDLStatementNode, to prevent the
117      * interference of insert/update/delete/DDL compilation and DDL execution,
118      * see beetle 3976, 4343, and $WS/language/SolutionsToConcurrencyIssues.txt
119      */

120     protected TableDescriptor lockTableForCompilation(TableDescriptor td)
121         throws StandardException
122     {
123         DataDictionary dd = getDataDictionary();
124
125         /* we need to lock only if the data dictionary is in DDL cache mode
126          */

127         if (dd.getCacheMode() == DataDictionary.DDL_MODE)
128         {
129             ConglomerateController heapCC;
130             TransactionController tc =
131                 getLanguageConnectionContext().getTransactionCompile();
132
133             heapCC = tc.openConglomerate(td.getHeapConglomerateId(),
134                                     false,
135                                     TransactionController.OPENMODE_FORUPDATE |
136                                     TransactionController.OPENMODE_FOR_LOCK_ONLY,
137                                     TransactionController.MODE_RECORD,
138                                     TransactionController.ISOLATION_SERIALIZABLE);
139             heapCC.close();
140             /*
141             ** Need to get TableDescriptor again after getting the lock, in
142             ** case for example, a concurrent add column thread commits
143             ** while we are binding.
144             */

145             String JavaDoc tableName = td.getName();
146             td = getTableDescriptor(td.getName(), getSchemaDescriptor(td.getSchemaName()));
147             if (td == null)
148             {
149                 throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, tableName);
150             }
151         }
152         return td;
153     }
154
155
156     /**
157      * Do code generation for this statement.
158      *
159      * @param byteCode the generated byte code for this statement.
160      * if non-null, then the byte code is saved
161      * here.
162      *
163      * @return A GeneratedClass for this statement
164      *
165      * @exception StandardException Thrown on error
166      */

167     public GeneratedClass generate(ByteArray byteCode) throws StandardException
168     {
169         // start the new activation class.
170
// it starts with the Execute method
171
// and the appropriate superclass (based on
172
// statement type, from inspecting the queryTree).
173

174         int nodeChoice = activationKind();
175
176         /* RESOLVE: Activation hierarchy was way too complicated
177          * and added no value. Simple thing to do was to simply
178          * leave calling code alone and to handle here and to
179          * eliminate unnecessary classes.
180          */

181         String JavaDoc superClass;
182         switch (nodeChoice)
183         {
184         case NEED_CURSOR_ACTIVATION:
185             superClass = ClassName.CursorActivation;
186             break;
187         case NEED_DDL_ACTIVATION:
188             return getClassFactory().loadGeneratedClass(
189                 "org.apache.derby.impl.sql.execute.ConstantActionActivation", null);
190
191         case NEED_NOTHING_ACTIVATION :
192         case NEED_ROW_ACTIVATION :
193         case NEED_PARAM_ACTIVATION :
194             superClass = ClassName.BaseActivation;
195             break;
196         default :
197             throw StandardException.newException(SQLState.LANG_UNAVAILABLE_ACTIVATION_NEED,
198                     String.valueOf(nodeChoice));
199         }
200
201         ActivationClassBuilder generatingClass = new ActivationClassBuilder(
202                                         superClass,
203                                         getCompilerContext());
204         MethodBuilder executeMethod = generatingClass.getExecuteMethod();
205
206
207         /*
208         ** the resultSet variable is cached.
209         **
210         ** resultSet = (resultSet == null) ? ... : resultSet
211         */

212
213         executeMethod.pushThis();
214         executeMethod.getField(ClassName.BaseActivation, "resultSet", ClassName.ResultSet);
215         executeMethod.conditionalIfNull();
216
217             /* We should generate the result set here. However, the generated
218              * code size may be too big to fit in a conditional statement for
219              * Java compiler to handle (it has a jump/branch step limit). For
220              * example, a extremely huge insert is issued with many many rows
221              * (beetle 4293). We fork a worker method here to get the
222              * generated result set, pass our parameter to it and call it.
223              */

224             MethodBuilder mbWorker = generatingClass.getClassBuilder().newMethodBuilder(
225                                                         Modifier.PROTECTED,
226                                                         ClassName.ResultSet,
227                                                         "fillResultSet");
228             mbWorker.addThrownException(ClassName.StandardException);
229
230             // we expect to get back an expression that will give a resultSet
231
// the nodes use the generatingClass: they add expression functions
232
// to it, and then use those functions in their expressions.
233
generate(generatingClass, mbWorker);
234
235             mbWorker.methodReturn();
236             mbWorker.complete();
237             executeMethod.pushThis();
238             executeMethod.callMethod(VMOpcode.INVOKEVIRTUAL, (String JavaDoc) null,
239                                      "fillResultSet", ClassName.ResultSet, 0);
240
241         executeMethod.startElseCode(); // this is here as the compiler only supports ? :
242
executeMethod.pushThis();
243             executeMethod.getField(ClassName.BaseActivation, "resultSet", ClassName.ResultSet);
244         executeMethod.completeConditional();
245
246         executeMethod.pushThis();
247         executeMethod.swap();
248         executeMethod.putField(ClassName.BaseActivation, "resultSet", ClassName.ResultSet);
249
250         executeMethod.endStatement();
251
252         // wrap up the activation class definition
253
// generate on the tree gave us back the newExpr
254
// for getting a result set on the tree.
255
// we put it in a return statement and stuff
256
// it in the execute method of the activation.
257
// The generated statement is the expression:
258
// the activation class builder takes care of constructing it
259
// for us, given the resultSetExpr to use.
260
// return (this.resultSet = #resultSetExpr);
261
generatingClass.finishExecuteMethod(this instanceof CursorNode);
262
263         // wrap up the constructor by putting a return at the end of it
264
generatingClass.finishConstructor();
265
266         try {
267             // cook the completed class into a real class
268
// and stuff it into activationClass
269
GeneratedClass activationClass = generatingClass.getGeneratedClass(byteCode);
270
271             return activationClass;
272         } catch (StandardException e) {
273             
274             String JavaDoc msgId = e.getMessageId();
275
276             if (SQLState.GENERATED_CLASS_LIMIT_EXCEEDED.equals(msgId)
277                     || SQLState.GENERATED_CLASS_LINKAGE_ERROR.equals(msgId))
278             {
279                 throw StandardException.newException(
280                         SQLState.LANG_QUERY_TOO_COMPLEX, e);
281             }
282     
283             throw e;
284         }
285      }
286 }
287
Popular Tags