KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.SQLToJavaValueNode
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.compiler.MethodBuilder;
25 import org.apache.derby.iapi.services.compiler.LocalField;
26
27 import org.apache.derby.iapi.services.sanity.SanityManager;
28
29 import org.apache.derby.iapi.types.JSQLType;
30
31 import org.apache.derby.iapi.types.DataValueDescriptor;
32 import org.apache.derby.iapi.types.DataTypeDescriptor;
33
34 import org.apache.derby.iapi.sql.compile.TypeCompiler;
35
36 import org.apache.derby.iapi.sql.Activation;
37
38 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
39 import org.apache.derby.iapi.error.StandardException;
40 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
41 import org.apache.derby.iapi.sql.compile.Visitable;
42 import org.apache.derby.iapi.sql.compile.Visitor;
43
44 import org.apache.derby.iapi.reference.ClassName;
45
46 import org.apache.derby.iapi.util.JBitSet;
47 import org.apache.derby.iapi.services.classfile.VMOpcode;
48
49 import java.lang.reflect.Modifier JavaDoc;
50
51 import java.util.Vector JavaDoc;
52
53 /**
54  * This node type converts a value in the SQL domain to a value in the Java
55  * domain.
56  */

57
58 public class SQLToJavaValueNode extends JavaValueNode
59 {
60     ValueNode value;
61
62     LocalField returnsNullOnNullState;
63
64     /**
65      * Constructor for a SQLToJavaValueNode
66      *
67      * @param value A ValueNode representing a SQL value to convert to
68      * the Java domain.
69      */

70
71     public void init(Object JavaDoc value)
72     {
73         this.value = (ValueNode) value;
74     }
75
76     /**
77      * Prints the sub-nodes of this object. See QueryTreeNode.java for
78      * how tree printing is supposed to work.
79      *
80      * @param depth The depth of this node in the tree
81      */

82
83     public void printSubNodes(int depth)
84     {
85         if (SanityManager.DEBUG)
86         {
87             int parm;
88
89             super.printSubNodes(depth);
90             if (value != null)
91             {
92                 printLabel(depth, "value: ");
93                 value.treePrint(depth + 1);
94             }
95         }
96     }
97
98     /**
99       * Returns the name of the java class type that this node coerces to.
100       *
101       * @return name of java class type
102       *
103       */

104     public String JavaDoc getJavaTypeName()
105     throws StandardException
106     {
107         JSQLType myType = getJSQLType();
108
109         if ( myType == null ) { return ""; }
110         else { return mapToTypeID( myType ).getCorrespondingJavaTypeName(); }
111     }
112
113     /**
114       * Returns the name of the java primitive type that this node coerces to.
115       *
116       * @return name of java primitive type
117       *
118       * @exception StandardException Thrown on error
119       */

120     public String JavaDoc getPrimitiveTypeName()
121         throws StandardException
122     {
123         JSQLType myType = getJSQLType();
124
125         if ( myType == null )
126         {
127             return "";
128         }
129         else
130         {
131             return
132                 getTypeCompiler(mapToTypeID( myType )).
133                                         getCorrespondingPrimitiveTypeName();
134         }
135     }
136
137     /**
138       * Get the JSQLType that corresponds to this node. Could be a SQLTYPE,
139       * a Java primitive, or a Java class.
140       *
141       * Overrides method in JavaValueNode.
142       *
143       * @return the corresponding JSQLType
144       *
145       */

146     public JSQLType getJSQLType () throws StandardException
147     {
148         if ( jsqlType == null )
149         {
150             if ( value.requiresTypeFromContext())
151             {
152                 ParameterNode pn;
153                 if (value instanceof UnaryOperatorNode)
154                     pn = ((UnaryOperatorNode)value).getParameterOperand();
155                 else
156                     pn = (ParameterNode) (value);
157                 jsqlType = pn.getJSQLType();
158             }
159             else
160             {
161                 DataTypeDescriptor dtd = value.getTypeServices();
162                 if (dtd != null)
163                     jsqlType = new JSQLType( dtd );
164             }
165         }
166
167         return jsqlType;
168     }
169
170
171     /**
172      * Set the clause that this node appears in.
173      *
174      * @param clause The clause that this node appears in.
175      */

176     public void setClause(int clause)
177     {
178         super.setClause(clause);
179         value.setClause(clause);
180     }
181
182     /**
183      * Bind this expression. This means binding the sub-expressions,
184      * as well as figuring out what the return type is for this expression.
185      *
186      * @param fromList The FROM list for the query this
187      * expression is in, for binding columns.
188      * @param subqueryList The subquery list being built as we find
189      * SubqueryNodes
190      * @param aggregateVector The aggregate vector being built as we find AggregateNodes
191      *
192      * @return this
193      *
194      * @exception StandardException Thrown on error
195      */

196
197     public JavaValueNode bindExpression(
198         FromList fromList, SubqueryList subqueryList,
199         Vector JavaDoc aggregateVector)
200             throws StandardException
201     {
202         /* Bind the expression under us */
203         value = value.bindExpression(fromList, subqueryList,
204                               aggregateVector);
205
206         return this;
207     }
208
209     /**
210      * Remap all ColumnReferences in this tree to be clones of the
211      * underlying expression.
212      *
213      * @return JavaValueNode The remapped expression tree.
214      *
215      * @exception StandardException Thrown on error
216      */

217     public JavaValueNode remapColumnReferencesToExpressions()
218         throws StandardException
219     {
220         value = value.remapColumnReferencesToExpressions();
221         return this;
222     }
223
224     /**
225      * Categorize this predicate. Initially, this means
226      * building a bit map of the referenced tables for each predicate.
227      * If the source of this ColumnReference (at the next underlying level)
228      * is not a ColumnReference or a VirtualColumnNode then this predicate
229      * will not be pushed down.
230      *
231      * For example, in:
232      * select * from (select 1 from s) a (x) where x = 1
233      * we will not push down x = 1.
234      * NOTE: It would be easy to handle the case of a constant, but if the
235      * inner SELECT returns an arbitrary expression, then we would have to copy
236      * that tree into the pushed predicate, and that tree could contain
237      * subqueries and method calls.
238      * RESOLVE - revisit this issue once we have views.
239      *
240      * @param referencedTabs JBitSet with bit map of referenced FromTables
241      * @param simplePredsOnly Whether or not to consider method
242      * calls, field references and conditional nodes
243      * when building bit map
244      *
245      * @return boolean Whether or not source.expression is a ColumnReference
246      * or a VirtualColumnNode.
247      *
248      * @exception StandardException Thrown on error
249      */

250     public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)
251         throws StandardException
252     {
253         return value.categorize(referencedTabs, simplePredsOnly);
254     }
255
256     /**
257      * Preprocess an expression tree. We do a number of transformations
258      * here (including subqueries, IN lists, LIKE and BETWEEN) plus
259      * subquery flattening.
260      * NOTE: This is done before the outer ResultSetNode is preprocessed.
261      *
262      * @param numTables Number of tables in the DML Statement
263      * @param outerFromList FromList from outer query block
264      * @param outerSubqueryList SubqueryList from outer query block
265      * @param outerPredicateList PredicateList from outer query block
266      *
267      * @exception StandardException Thrown on error
268      */

269     public void preprocess(int numTables,
270                             FromList outerFromList,
271                             SubqueryList outerSubqueryList,
272                             PredicateList outerPredicateList)
273                             throws StandardException
274     {
275         value.preprocess(numTables,
276                          outerFromList, outerSubqueryList,
277                          outerPredicateList);
278     }
279
280     /**
281      * Return the variant type for the underlying expression.
282      * The variant type can be:
283      * VARIANT - variant within a scan
284      * (method calls and non-static field access)
285      * SCAN_INVARIANT - invariant within a scan
286      * (column references from outer tables)
287      * QUERY_INVARIANT - invariant within the life of a query
288      * (constant expressions)
289      *
290      * @return The variant type for the underlying expression.
291      * @exception StandardException thrown on error
292      */

293     protected int getOrderableVariantType() throws StandardException
294     {
295         return value.getOrderableVariantType();
296     }
297
298     ///////////////////////////////////////////////////////////////////////
299
//
300
// CODE GENERATION METHODS
301
//
302
///////////////////////////////////////////////////////////////////////
303

304
305     /**
306      * Generate code to get the Java value out of a SQL value.
307      *
308      * Every SQL type has a corresponding Java type. The getObject() method
309      * on the SQL type gets the right Java type.
310      *
311      * The generated code will be:
312      *
313      * (<Java type name>) ((DataValueDescriptor)
314      * <generated value>.getObject())
315      *
316      * where <Java type name> comes from the getCorrespondingJavaTypeName()
317      * method of the value's TypeId.
318      *
319      * @param acb The ExpressionClassBuilder for the class being built
320      * @param mb The method the expression will go into
321      *
322      *
323      * @exception StandardException Thrown on error
324      */

325
326     public void generateExpression(ExpressionClassBuilder acb,
327                                             MethodBuilder mb)
328                                     throws StandardException
329     {
330         /* Compile the expression under us */
331         generateSQLValue( acb, mb );
332
333         /* now cast the SQLValue to a Java value */
334         generateJavaValue( acb, mb);
335     }
336
337     /**
338      * Generate the SQLvalue that this node wraps.
339      *
340      * @param acb The ExpressionClassBuilder for the class being built
341      * @param mb The method the expression will go into
342      *
343      *
344      * @exception StandardException Thrown on error
345      */

346
347     public void generateSQLValue(ExpressionClassBuilder acb,
348                                             MethodBuilder mb)
349                                     throws StandardException
350     {
351         value.generateExpression(acb, mb);
352     }
353
354     /**
355      * Generate code to cast the SQLValue to a Java value.
356      *
357      *
358      * @param acb The ExpressionClassBuilder for the class being built
359      * @param mbex The method the expression will go into
360      *
361      *
362      * @exception StandardException Thrown on error
363      */

364
365     public void generateJavaValue
366     (
367         ExpressionClassBuilder acb,
368         MethodBuilder mbex
369     )
370         throws StandardException
371     {
372         /* If this is a conversion to a primitive type, then call the
373          * appropriate method for getting the primitive value and
374          * cast it to the primitive type.
375          * NOTE: We first call Activation.nullToPrimitiveTest(),
376          * which will throw a StandardException if the value is null
377          */

378         if ( isPrimitiveType() || mustCastToPrimitive() )
379         {
380             String JavaDoc primitiveTN = value.getTypeCompiler().getCorrespondingPrimitiveTypeName();
381
382             /* Put the code to check if the object is null and to
383              * get the primitive value in a method call. This is
384              * necessary because we are generating an expression here and
385              * cannot have multiple statements.
386              * The method call will take SQLValue as a parameter.
387              */

388             String JavaDoc[] pd = new String JavaDoc[1];
389             pd[0] = getSQLValueInterfaceName(); // parameter "param1"
390

391             MethodBuilder mb = acb.newGeneratedFun(primitiveTN, Modifier.PRIVATE, pd);
392
393             mb.getParameter(0);
394
395             if (returnsNullOnNullState != null)
396             {
397                 generateReturnsNullOnNullCheck(mb);
398             }
399             else
400             {
401                 mb.dup();
402                 mb.upCast(ClassName.DataValueDescriptor);
403                 mb.push(primitiveTN);
404                 mb.callMethod(VMOpcode.INVOKESTATIC, ClassName.BaseActivation, "nullToPrimitiveTest", "void", 2);
405             }
406
407             // stack is dvd
408

409             /* Generate the code to get the primitive value */
410             mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.DataValueDescriptor,
411                                 value.getTypeCompiler().getPrimitiveMethodName(), primitiveTN, 0);
412
413             mb.methodReturn();
414             mb.complete();
415
416             /* Generate the call to the new method, with the parameter */
417
418             mbex.pushThis();
419             mbex.swap(); // caller pushed out parameter
420
mbex.callMethod(VMOpcode.INVOKEVIRTUAL, (String JavaDoc) null, mb.getName(), primitiveTN, 1);
421         }
422         else
423         {
424             if (returnsNullOnNullState != null)
425                 generateReturnsNullOnNullCheck(mbex);
426
427             /* Call getObject() to get the right type of Java value */
428             mbex.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.DataValueDescriptor, "getObject",
429                                         "java.lang.Object", 0);
430
431             mbex.cast(value.getTypeId().getCorrespondingJavaTypeName());
432         }
433     }
434
435     /**
436         Generate the code for the returns Null on Null input check..
437         Stack must contain the DataDescriptorValue.
438     */

439
440     private void generateReturnsNullOnNullCheck(MethodBuilder mb)
441     {
442         mb.dup();
443         mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Storable,
444                                 "isNull", "boolean", 0);
445
446         mb.conditionalIf();
447           mb.push(true);
448         mb.startElseCode();
449           mb.getField(returnsNullOnNullState);
450         mb.completeConditional();
451         
452         mb.setField(returnsNullOnNullState);
453     }
454
455
456     /**
457       * Get the type name of the SQLValue we generate.
458       *
459       * @return name of interface corresponding to SQLValue
460       *
461       *
462       * @exception StandardException Thrown on error
463       */

464     public String JavaDoc getSQLValueInterfaceName()
465         throws StandardException
466     {
467         return value.getTypeCompiler().interfaceName();
468     }
469
470     ///////////////////////////////////////////////////////////////////////
471
//
472
// OTHER VALUE NODE METHODS
473
//
474
///////////////////////////////////////////////////////////////////////
475

476
477     /**
478      * Get the SQL ValueNode that is being converted to a JavaValueNode
479      *
480      * @return The underlying SQL ValueNode
481      */

482     ValueNode getSQLValueNode()
483     {
484         return value;
485     }
486
487     /** @see ValueNode#getConstantValueAsObject
488      *
489      * @exception StandardException Thrown on error
490      */

491     Object JavaDoc getConstantValueAsObject()
492         throws StandardException
493     {
494         return value.getConstantValueAsObject();
495     }
496
497     /**
498      * Accept a visitor, and call v.visit()
499      * on child nodes as necessary.
500      *
501      * @param v the visitor
502      *
503      * @exception StandardException on error
504      */

505     public Visitable accept(Visitor v)
506         throws StandardException
507     {
508         Visitable returnNode = v.visit(this);
509     
510         if (v.skipChildren(this))
511         {
512             return returnNode;
513         }
514
515         if (value != null && !v.stopTraversal())
516         {
517             value = (ValueNode)value.accept(v);
518         }
519
520         return returnNode;
521     }
522 }
523
Popular Tags