KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.NonStaticMethodCallNode
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.reference.SQLState;
25
26 import org.apache.derby.iapi.services.context.ContextManager;
27
28 import org.apache.derby.iapi.sql.compile.CompilerContext;
29
30 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
31 import org.apache.derby.iapi.reference.SQLState;
32 import org.apache.derby.iapi.error.StandardException;
33 import org.apache.derby.iapi.store.access.Qualifier;
34
35
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.services.loader.ClassInspector;
41
42 import org.apache.derby.iapi.services.compiler.MethodBuilder;
43 import org.apache.derby.iapi.services.sanity.SanityManager;
44
45 import org.apache.derby.iapi.types.JSQLType;
46
47 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
48 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
49 import org.apache.derby.iapi.error.ExceptionSeverity;
50 import org.apache.derby.iapi.util.JBitSet;
51 import org.apache.derby.iapi.services.classfile.VMOpcode;
52
53 import org.apache.derby.catalog.AliasInfo;
54
55 import java.lang.reflect.Modifier JavaDoc;
56
57 import java.util.Vector JavaDoc;
58
59 /**
60  * A NonStaticMethodCallNode is really a node to represent a (static or non-static)
61  * method call from an object (as opposed to a static method call from a class.
62  */

63 public class NonStaticMethodCallNode extends MethodCallNode
64 {
65     /*
66     ** The receiver for a non-static method call is an object, represented
67     ** by a ValueNode.
68     */

69     JavaValueNode receiver;
70
71     /* Is this a static method call? Assume non-static call */
72     private boolean isStatic;
73
74     /**
75      * Initializer for a NonStaticMethodCallNode
76      *
77      * @param methodName The name of the method to call
78      * @param receiver A JavaValueNode representing the receiving object
79      * @exception StandardException Thrown on error
80      */

81     public void init(
82                             Object JavaDoc methodName,
83                             Object JavaDoc receiver)
84             throws StandardException
85     {
86         super.init(methodName);
87
88         /*
89         ** If the receiver is a Java value that has been converted to a
90         ** SQL value, get rid of the conversion and just use the Java value
91         ** as-is. If the receiver is a "normal" SQL value, then convert
92         ** it to a Java value to use as the receiver.
93         */

94         if (receiver instanceof JavaToSQLValueNode)
95         {
96             this.receiver = ((JavaToSQLValueNode) receiver).
97                                         getJavaValueNode();
98         }
99         else
100         {
101             this.receiver = (JavaValueNode) getNodeFactory().
102                                 getNode(
103                                     C_NodeTypes.SQL_TO_JAVA_VALUE_NODE,
104                                     receiver,
105                                     getContextManager());
106 // System.out.println("NonStaticMethodCallNode.init() receiver = "+receiver);
107
// get nulpointer because not .bind?
108
// System.out.println("\ttypecompiler = "+((ValueNode)receiver).getTypeCompiler());
109
// System.out.println("\tdtd = "+((ValueNode)receiver).getTypeServices());
110
// System.out.println("\ttypeid = "+((ValueNode)receiver).getTypeServices().getTypeId());
111
}
112     }
113
114     /**
115      * Bind this expression. This means binding the sub-expressions,
116      * as well as figuring out what the return type is for this expression.
117      *
118      * @param fromList The FROM list for the query this
119      * expression is in, for binding columns.
120      * @param subqueryList The subquery list being built as we find SubqueryNodes
121      * @param aggregateVector The aggregate vector being built as we find AggregateNodes
122      *
123      * @return this
124      *
125      * @exception StandardException Thrown on error
126      */

127
128     public JavaValueNode bindExpression(
129         FromList fromList, SubqueryList subqueryList,
130         Vector JavaDoc aggregateVector)
131             throws StandardException
132     {
133         boolean nullParameter = false;
134         String JavaDoc[] parmTypeNames;
135
136         /* NULL and ? not allowed as receivers */
137         if (receiver instanceof SQLToJavaValueNode)
138         {
139             ValueNode SQLValue =
140                             ((SQLToJavaValueNode) receiver).getSQLValueNode();
141
142             if (SanityManager.DEBUG)
143             SanityManager.ASSERT(!(SQLValue instanceof UntypedNullConstantNode),
144                 "UntypedNullConstantNode found as a receiver of a non-static method call");
145
146             //
147
// We don't allow methods off of naked unnamed "?" parameters.
148
// This is because we have no way of knowing the data type of
149
// a naked "?" parameter.
150
//
151
// However, if this "?" has actually been associated with a
152
// named "?paramName" parameter in a COPY PUBLICATION statement,
153
// then we have a type for it. Binding can continue.
154
//
155

156             if (SQLValue.requiresTypeFromContext())
157             {
158                 if ( SQLValue.getTypeServices() == null )
159                 { throw StandardException.newException(SQLState.LANG_PARAMETER_RECEIVER, methodName); }
160             }
161         }
162
163         bindParameters(fromList, subqueryList, aggregateVector);
164
165         /* Now we don't allow an alias static method call here (that has to
166          * use :: sign for any static call). If it gets here, it can't be
167          * alias static method call.
168          */

169         receiver = receiver.bindExpression(fromList, subqueryList, aggregateVector);
170
171         // Don't allow LOB types to be used as a method receiver
172
String JavaDoc type = receiver.getJSQLType().getSQLType().getTypeId().getSQLTypeName();
173         if ( type.equals("BLOB") || type.equals("CLOB") || type.equals("NCLOB") ) {
174             throw StandardException.newException(SQLState.LOB_AS_METHOD_ARGUMENT_OR_RECEIVER);
175         }
176
177         javaClassName = receiver.getJavaTypeName();
178
179         /* Not allowed to use a primitive type as a method receiver */
180         if (ClassInspector.primitiveType(javaClassName))
181         {
182             throw StandardException.newException(SQLState.LANG_PRIMITIVE_RECEIVER, methodName, javaClassName);
183         }
184
185         /* Resolve the method call */
186         resolveMethodCall(javaClassName, false);
187
188         /* Remember if method is static */
189         isStatic = Modifier.isStatic(method.getModifiers());
190
191         return this;
192     }
193
194     /**
195      * Categorize this predicate. Initially, this means
196      * building a bit map of the referenced tables for each predicate.
197      * If the source of this ColumnReference (at the next underlying level)
198      * is not a ColumnReference or a VirtualColumnNode then this predicate
199      * will not be pushed down.
200      *
201      * For example, in:
202      * select * from (select 1 from s) a (x) where x = 1
203      * we will not push down x = 1.
204      * NOTE: It would be easy to handle the case of a constant, but if the
205      * inner SELECT returns an arbitrary expression, then we would have to copy
206      * that tree into the pushed predicate, and that tree could contain
207      * subqueries and method calls.
208      * RESOLVE - revisit this issue once we have views.
209      *
210      * @param referencedTabs JBitSet with bit map of referenced FromTables
211      * @param simplePredsOnly Whether or not to consider method
212      * calls, field references and conditional nodes
213      * when building bit map
214      *
215      * @return boolean Whether or not source.expression is a ColumnReference
216      * or a VirtualColumnNode.
217      * @exception StandardException Thrown on error
218      */

219     public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)
220         throws StandardException
221     {
222         /* We stop here when only considering simple predicates
223          * as we don't consider method calls when looking
224          * for null invariant predicates.
225          */

226         if (simplePredsOnly)
227         {
228             return false;
229         }
230
231         boolean pushable = true;
232
233         pushable = pushable && super.categorize(referencedTabs, simplePredsOnly);
234
235         if (receiver != null)
236         {
237             pushable = pushable && receiver.categorize(referencedTabs, simplePredsOnly);
238         }
239
240         return pushable;
241     }
242
243     /**
244      * Return the variant type for the underlying expression.
245      * The variant type can be:
246      * VARIANT - variant within a scan
247      * (non-static field access)
248      * SCAN_INVARIANT - invariant within a scan
249      * (column references from outer tables)
250      * QUERY_INVARIANT - invariant within the life of a query
251      * (constant expressions)
252      *
253      * @return The variant type for the underlying expression.
254      */

255     protected int getOrderableVariantType() throws StandardException
256     {
257         int receiverVariant = receiver.getOrderableVariantType();
258
259         if (receiverVariant > Qualifier.SCAN_INVARIANT) {
260             
261             // If the method call is related to a trigger then the return
262
// values are SCAN_INVARIANT even though their calls look QUERY_INVARIANT
263
// because they take no parameters.
264
if (receiver.getJavaTypeName().equals("org.apache.derby.iapi.db.TriggerExecutionContext"))
265                 receiverVariant = Qualifier.SCAN_INVARIANT;
266         }
267
268
269         int thisVariant = super.getOrderableVariantType();
270         if (receiverVariant < thisVariant) //return the more variant one
271
return receiverVariant;
272         return thisVariant;
273     }
274
275     /**
276      * Remap all ColumnReferences in this tree to be clones of the
277      * underlying expression.
278      *
279      * @return JavaValueNode The remapped expression tree.
280      *
281      * @exception StandardException Thrown on error
282      */

283     public JavaValueNode remapColumnReferencesToExpressions()
284         throws StandardException
285     {
286         if (receiver != null)
287         {
288             receiver.remapColumnReferencesToExpressions();
289         }
290
291         return super.remapColumnReferencesToExpressions();
292     }
293
294     /**
295      * Prints the sub-nodes of this object. See QueryTreeNode.java for
296      * how tree printing is supposed to work.
297      *
298      * @param depth The depth of this node in the tree
299      */

300
301     public void printSubNodes(int depth)
302     {
303         if (SanityManager.DEBUG)
304         {
305             int parm;
306
307             super.printSubNodes(depth);
308             if (receiver != null)
309             {
310                 printLabel(depth, "receiver :");
311                 receiver.treePrint(depth + 1);
312             }
313         }
314     }
315
316     /**
317      * Preprocess an expression tree. We do a number of transformations
318      * here (including subqueries, IN lists, LIKE and BETWEEN) plus
319      * subquery flattening.
320      * NOTE: This is done before the outer ResultSetNode is preprocessed.
321      *
322      * @param numTables Number of tables in the DML Statement
323      * @param outerFromList FromList from outer query block
324      * @param outerSubqueryList SubqueryList from outer query block
325      * @param outerPredicateList PredicateList from outer query block
326      *
327      * @exception StandardException Thrown on error
328      */

329     public void preprocess(int numTables,
330                             FromList outerFromList,
331                             SubqueryList outerSubqueryList,
332                             PredicateList outerPredicateList)
333                             throws StandardException
334     {
335         super.preprocess(numTables,
336                          outerFromList, outerSubqueryList,
337                          outerPredicateList);
338         receiver.preprocess(numTables,
339                             outerFromList, outerSubqueryList,
340                             outerPredicateList);
341
342     }
343
344     /**
345      * Do code generation for this method call
346      *
347      * @param acb The ExpressionClassBuilder for the class we're generating
348      * @param mb The method the expression will go into
349      *
350      *
351      * @exception StandardException Thrown on error
352      */

353
354     public void generateExpression(ExpressionClassBuilder acb,
355                                             MethodBuilder mb)
356                                     throws StandardException
357     {
358         boolean inConditional = false;
359         /*
360         ** If this method returns its value to the Java domain,
361         ** generate the receiver and put the value in a field (only if
362         ** this method does not return a primitive type). If it
363         ** returns its value to the SQL domain, it's up to the JavaToSQLNode
364         ** to call generateReceiver().
365         **
366         ** Also, don't do this if the return value from this method
367         ** call will be discarded. This is the case for a CALL statement.
368         ** One reason we don't want to do this for a CALL statement
369         ** is that the ?: operator cannot be made into a statement.
370         */

371         if ( ( ! valueReturnedToSQLDomain()) && ( ! returnValueDiscarded()))
372         {
373             if (generateReceiver(acb, mb, receiver))
374             {
375                 /*
376                 ** If the above did generate the expression, let's test it for
377                 ** a null value.
378                 */

379                 /*
380                 ** Generate the following to test for null:
381                 **
382                 ** (receiverExpression == null) ?
383                 */

384
385                 inConditional = true;
386                 mb.conditionalIfNull();
387                 mb.pushNull(getJavaTypeName());
388                 mb.startElseCode();
389             }
390         }
391
392         /*
393         ** Generate the following:
394         **
395         ** <receiver>.<method name>(<param> (, <param> )* )
396         **
397         ** for non-static calls.
398         **
399         ** Refer to the field holding the receiver, if there is any.
400         */

401
402         Class JavaDoc declaringClass = method.getDeclaringClass();
403         
404         /*
405         ** If it's an interface, generate an interface method call, if it's a static,
406         ** generate a static method call, otherwise generate a regular method call.
407         */

408
409         short methodType;
410
411         if (declaringClass.isInterface())
412             methodType = VMOpcode.INVOKEINTERFACE;
413         else if (isStatic)
414             methodType = VMOpcode.INVOKESTATIC;
415         else
416             methodType = VMOpcode.INVOKEVIRTUAL;
417
418         getReceiverExpression(acb, mb, receiver);
419         if (isStatic)
420             mb.endStatement(); // PUSHCOMPILER ???
421

422         int nargs = generateParameters(acb, mb);
423
424         mb.callMethod(methodType, declaringClass.getName(), methodName, getJavaTypeName(), nargs);
425
426         if (inConditional)
427             mb.completeConditional();
428     }
429
430     /**
431      * Generate the expression that evaluates to the receiver. This is
432      * for the case where a java expression is being returned to the SQL
433      * domain, and we need to check whether the receiver is null (if so,
434      * the SQL value should be set to null, and this Java expression
435      * not evaluated). Instance method calls and field references have
436      * receivers, while class method calls and calls to constructors do
437      * not. If this Java expression does not have a receiver, this method
438      * returns null.
439      *
440      * Only generate the receiver once and cache it in a field. This is
441      * because there will be two references to the receiver, and we want
442      * to evaluate it only once.
443      *
444      *
445      * @param acb The ExpressionClassBuilder for the class being built
446      * @param mb The method the expression will go into
447      *
448      * @return true if compiled receiver, false otherwise.
449      *
450      * @exception StandardException Thrown on error
451      */

452     protected boolean generateReceiver(ExpressionClassBuilder acb,
453                                             MethodBuilder mb)
454                                     throws StandardException
455     {
456         /*
457         ** Let's pretend that a call to a static method doesn't have a
458         ** receiver, since the method call is actually to the class,
459         ** and can be made even if the receiver is null (that is, we
460         ** always want to call a static method, even if the receiver is null).
461         */

462         if (isStatic)
463             return false;
464         
465         return generateReceiver(acb, mb, receiver);
466     }
467
468     /**
469      * Accept a visitor, and call v.visit()
470      * on child nodes as necessary.
471      *
472      * @param v the visitor
473      *
474      * @exception StandardException on error
475      */

476     public Visitable accept(Visitor v)
477         throws StandardException
478     {
479         if (v.skipChildren(this))
480         {
481             return v.visit(this);
482         }
483
484         Visitable returnNode = super.accept(v);
485
486         if (receiver != null && !v.stopTraversal())
487         {
488             receiver = (JavaValueNode)receiver.accept(v);
489         }
490
491         return returnNode;
492     }
493 }
494
Popular Tags