KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.CallStatementNode
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.dictionary.DataDictionary;
29 import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
30
31 import org.apache.derby.iapi.sql.ResultSet;
32 import org.apache.derby.iapi.sql.Activation;
33 import org.apache.derby.iapi.sql.ResultDescription;
34
35 import org.apache.derby.iapi.sql.compile.CompilerContext;
36 import org.apache.derby.iapi.sql.compile.Visitable;
37 import org.apache.derby.iapi.sql.compile.Visitor;
38 import org.apache.derby.iapi.sql.compile.C_NodeTypes;
39
40 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
41 import org.apache.derby.iapi.sql.conn.Authorizer;
42
43 import org.apache.derby.iapi.services.loader.GeneratedMethod;
44
45 import org.apache.derby.iapi.services.sanity.SanityManager;
46
47 import org.apache.derby.iapi.services.compiler.MethodBuilder;
48
49 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
50 import org.apache.derby.iapi.reference.ClassName;
51 import org.apache.derby.iapi.services.classfile.VMOpcode;
52
53 import org.apache.derby.catalog.types.RoutineAliasInfo;
54 import org.apache.derby.iapi.reference.SQLState;
55
56 import java.lang.reflect.Modifier JavaDoc;
57
58 import java.util.Vector JavaDoc;
59
60 /**
61  * An CallStatementNode represents a CALL <procedure> statement.
62  * It is the top node of the query tree for that statement.
63  * A procedure call is very simple.
64  *
65  * CALL [<schema>.]<procedure>(<args>)
66  *
67  * <args> are either constants or parameter markers.
68  * This implementation assumes that no subqueries or aggregates
69  * can be in the argument list.
70  *
71  * A procedure is always represented by a MethodCallNode.
72  *
73  * @author Jerry Brenner
74  */

75 public class CallStatementNode extends DMLStatementNode
76 {
77     /**
78      * The method call for the Java procedure. Guaranteed to be
79      * a JavaToSQLValueNode wrapping a MethodCallNode by checks
80      * in the parser.
81      */

82     private JavaToSQLValueNode methodCall;
83
84
85     /**
86      * Initializer for a CallStatementNode.
87      *
88      * @param methodCall The expression to "call"
89      */

90
91     public void init(Object JavaDoc methodCall)
92     {
93         super.init(null);
94         this.methodCall = (JavaToSQLValueNode) methodCall;
95         this.methodCall.getJavaValueNode().markForCallStatement();
96     }
97
98     /**
99      * Convert this object to a String. See comments in QueryTreeNode.java
100      * for how this should be done for tree printing.
101      *
102      * @return This object as a String
103      */

104
105     public String JavaDoc toString()
106     {
107         if (SanityManager.DEBUG)
108         {
109             return "CALL " + methodCall.toString() + "\n" +
110                 super.toString();
111         }
112         else
113         {
114             return "";
115         }
116     }
117
118     public String JavaDoc statementToString()
119     {
120         return "CALL";
121     }
122
123     /**
124      * Prints the sub-nodes of this object. See QueryTreeNode.java for
125      * how tree printing is supposed to work.
126      *
127      * @param depth The depth of this node in the tree
128      */

129
130     public void printSubNodes(int depth)
131     {
132         if (SanityManager.DEBUG)
133         {
134             super.printSubNodes(depth);
135
136             if (methodCall != null)
137             {
138                 printLabel(depth, "methodCall: ");
139                 methodCall.treePrint(depth + 1);
140             }
141         }
142     }
143
144     /**
145      * Bind this UpdateNode. This means looking up tables and columns and
146      * getting their types, and figuring out the result types of all
147      * expressions, as well as doing view resolution, permissions checking,
148      * etc.
149      * <p>
150      * Binding an update will also massage the tree so that
151      * the ResultSetNode has a single column, the RID.
152      *
153      * @return The bound query tree
154      *
155      * @exception StandardException Thrown on error
156      */

157
158     public QueryTreeNode bind() throws StandardException
159     {
160         DataDictionary dd = getDataDictionary();
161
162         if (SanityManager.DEBUG)
163             SanityManager.ASSERT((dd != null), "Failed to get data dictionary");
164
165         getCompilerContext().pushCurrentPrivType(getPrivType());
166         methodCall = (JavaToSQLValueNode) methodCall.bindExpression(
167                             (FromList) getNodeFactory().getNode(
168                                 C_NodeTypes.FROM_LIST,
169                                 getNodeFactory().doJoinOrderOptimization(),
170                                 getContextManager()),
171                             null,
172                             null);
173
174         // Disallow creation of BEFORE triggers which contain calls to
175
// procedures that modify SQL data.
176
checkReliability();
177
178         getCompilerContext().popCurrentPrivType();
179         return this;
180     }
181
182     /**
183      * Optimize a DML statement (which is the only type of statement that
184      * should need optimizing, I think). This method over-rides the one
185      * in QueryTreeNode.
186      *
187      * This method takes a bound tree, and returns an optimized tree.
188      * It annotates the bound tree rather than creating an entirely
189      * new tree.
190      *
191      * Throws an exception if the tree is not bound, or if the binding
192      * is out of date.
193      *
194      * @return An optimized QueryTree
195      *
196      * @exception StandardException Thrown on error
197      */

198
199     public QueryTreeNode optimize() throws StandardException
200     {
201         DataDictionary dd = getDataDictionary();
202
203         if (SanityManager.DEBUG)
204         SanityManager.ASSERT((dd != null), "Failed to get data dictionary");
205
206         /* Preprocess the method call tree */
207         methodCall = (JavaToSQLValueNode) methodCall.preprocess(
208                                 getCompilerContext().getNumTables(),
209                                 (FromList) getNodeFactory().getNode(
210                                     C_NodeTypes.FROM_LIST,
211                                     getNodeFactory().doJoinOrderOptimization(),
212                                     getContextManager()),
213                                 (SubqueryList) null,
214                                 (PredicateList) null);
215
216         return this;
217     }
218
219     /**
220      * Code generation for CallStatementNode.
221      * The generated code will contain:
222      * o A generated void method for the user's method call.
223      *
224      * @param acb The ActivationClassBuilder for the class being built
225      * @param mb The method for the execute() method to be built
226      *
227      * @exception StandardException Thrown on error
228      */

229     public void generate(ActivationClassBuilder acb,
230                                 MethodBuilder mb)
231                             throws StandardException
232     {
233         JavaValueNode methodCallBody;
234
235         /* generate the parameters */
236         generateParameterValueSet(acb);
237
238         /*
239          * Skip over the JavaToSQLValueNode and call generate() for the JavaValueNode.
240          * (This skips over generated code which is unnecessary since we are throwing
241          * away any return value and which won't work with void methods.)
242          * generates:
243          * <methodCall.generate(acb)>;
244          * and adds it to userExprFun
245          */

246         methodCallBody = methodCall.getJavaValueNode();
247
248         /*
249         ** Tell the method call that its return value (if any) will be
250         ** discarded. This is so it doesn't generate the ?: operator
251         ** that would return null if the receiver is null. This is
252         ** important because the ?: operator cannot be made into a statement.
253         */

254         methodCallBody.markReturnValueDiscarded();
255
256         // this sets up the method
257
// generates:
258
// void userExprFun {
259
// method_call(<args>);
260
// }
261
//
262
// An expression function is used to avoid reflection.
263
// Since the arguments to a procedure are simple, this
264
// will be the only expression function and so it will
265
// be executed directly as e0.
266
MethodBuilder userExprFun = acb.newGeneratedFun("void", Modifier.PUBLIC);
267         userExprFun.addThrownException("java.lang.Exception");
268         methodCallBody.generate(acb, userExprFun);
269         userExprFun.endStatement();
270         userExprFun.methodReturn();
271         userExprFun.complete();
272
273         acb.pushGetResultSetFactoryExpression(mb);
274         acb.pushMethodReference(mb, userExprFun); // first arg
275
acb.pushThisAsActivation(mb); // arg 2
276
mb.callMethod(VMOpcode.INVOKEINTERFACE, (String JavaDoc) null, "getCallStatementResultSet", ClassName.ResultSet, 2);
277     }
278
279     public ResultDescription makeResultDescription()
280     {
281         return null;
282     }
283
284     /**
285      * Accept a visitor, and call v.visit()
286      * on child nodes as necessary.
287      *
288      * @param v the visitor
289      *
290      * @exception StandardException on error
291      */

292     public Visitable accept(Visitor v)
293         throws StandardException
294     {
295         if (v.skipChildren(this))
296         {
297             return v.visit(this);
298         }
299
300         Visitable returnNode = super.accept(v);
301
302         if (!v.stopTraversal())
303         {
304             methodCall = (JavaToSQLValueNode) methodCall.accept(v);
305         }
306
307         return returnNode;
308     }
309
310     /**
311      * Set default privilege of EXECUTE for this node.
312      */

313     int getPrivType()
314     {
315         return Authorizer.EXECUTE_PRIV;
316     }
317     
318     /**
319      * This method checks if the called procedure allows modification of SQL
320      * data. If yes, it cannot be compiled if the reliability is
321      * <code>CompilerContext.MODIFIES_SQL_DATA_PROCEDURE_ILLEGAL</code>. This
322      * reliability is set for BEFORE triggers in the create trigger node. This
323      * check thus disallows creation of BEFORE triggers which contain calls to
324      * procedures that modify SQL data in the trigger action statement.
325      *
326      * @throws StandardException
327      */

328     private void checkReliability() throws StandardException {
329         if(getSQLAllowedInProcedure() == RoutineAliasInfo.MODIFIES_SQL_DATA &&
330                 getCompilerContext().getReliability() == CompilerContext.MODIFIES_SQL_DATA_PROCEDURE_ILLEGAL)
331             throw StandardException.newException(SQLState.LANG_UNSUPPORTED_TRIGGER_PROC);
332     }
333     
334     /**
335      * This method checks the SQL allowed by the called procedure. This method
336      * should be called only after the procedure has been resolved.
337      *
338      * @return SQL allowed by the procedure
339      */

340     private short getSQLAllowedInProcedure() {
341         RoutineAliasInfo routineInfo = ((MethodCallNode)methodCall.getJavaValueNode()).routineInfo;
342         
343         // If this method is called before the routine has been resolved, routineInfo will be null
344
if (SanityManager.DEBUG)
345             SanityManager.ASSERT((routineInfo != null), "Failed to get routineInfo");
346
347         return routineInfo.getSQLAllowed();
348     }
349 }
350
Popular Tags