KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.ParameterNode
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 java.sql.Types JavaDoc;
25 import java.util.Enumeration JavaDoc;
26 import java.util.Vector JavaDoc;
27
28 import org.apache.derby.iapi.error.StandardException;
29 import org.apache.derby.iapi.reference.ClassName;
30 import org.apache.derby.iapi.reference.SQLState;
31 import org.apache.derby.iapi.services.classfile.VMOpcode;
32 import org.apache.derby.iapi.services.compiler.MethodBuilder;
33 import org.apache.derby.iapi.services.sanity.SanityManager;
34 import org.apache.derby.iapi.sql.compile.CompilerContext;
35 import org.apache.derby.iapi.store.access.Qualifier;
36 import org.apache.derby.iapi.types.DataTypeDescriptor;
37 import org.apache.derby.iapi.types.DataValueDescriptor;
38 import org.apache.derby.iapi.types.JSQLType;
39 import org.apache.derby.iapi.types.TypeId;
40
41 /**
42  * This node type represents a ? parameter.
43  *
44  * @author Jeff Lichtman
45  */

46
47 public class ParameterNode extends ValueNode
48 {
49
50     /*
51     ** The parameter number for this parameter. The numbers start at 0.
52     */

53     private int parameterNumber;
54
55     /*
56     ** Pointer to the array in the DMLStatementNode that holds the
57     ** DataTypeServices for the parameters. When each parameter is
58     ** bound, it fills in its type descriptor in this array. Note that
59     ** the array is allocated in the parser, but the individual elements
60     ** are not filled in until their corresponding parameters are bound.
61     */

62
63     private DataTypeDescriptor[] typeServices;
64
65     /*
66     ** The default value for this parameter. Currently, the only
67     ** reason for a parameter having a default value is for a
68     ** stored prepared statement, where they are supplied for
69     ** optimization.
70     */

71     private DataValueDescriptor defaultValue;
72
73     /**
74       * This ParameterNode may turn up as an argument to a replicated Work Unit.
75       * If so, the remote system will have figured out the type of this node.
76       * That's what this variable is for.
77       */

78     private JSQLType jsqlType;
79
80     private int orderableVariantType = Qualifier.QUERY_INVARIANT;
81
82     /**
83      * By default, we assume we are just a normal, harmless
84      * little ole parameter. But sometimes we may be a return
85      * parameter (e.g. ? = CALL myMethod()).
86      */

87     private ValueNode returnOutputParameter;
88
89     /**
90      * Constructor for use by the NodeFactory
91      */

92     public ParameterNode()
93     {
94     }
95
96     /**
97      * Initializer for a ParameterNode.
98      *
99      * @param parameterNumber The number of this parameter,
100      * (unique per query starting at 0)
101      * @param defaultValue The default value for this parameter
102      *
103      */

104
105     public void init(Object JavaDoc parameterNumber, Object JavaDoc defaultValue)
106     {
107         this.defaultValue = (DataValueDescriptor) defaultValue;
108         this.parameterNumber = ((Integer JavaDoc) parameterNumber).intValue();
109     }
110
111     /**
112      * Get the parameter number
113      *
114      * @return The parameter number
115      */

116
117     int getParameterNumber()
118     {
119         return parameterNumber;
120     }
121
122     /**
123      * Set the descriptor array
124      *
125      * @param descriptors The array of DataTypeServices to fill in when the parameters
126      * are bound.
127      */

128
129     void setDescriptors(DataTypeDescriptor[] descriptors)
130     {
131
132         // The following is commented out for #3546, for create publication
133
// or target ddl creations there could be multiple statements trying
134
// to bind their own parameters. So the following assumptions does not
135
// hold true.
136

137     // if (SanityManager.DEBUG)
138
// SanityManager.ASSERT(typeServices == null,
139
// "Attempt to re-set typeServices");
140

141         typeServices = descriptors;
142     }
143
144     /**
145      * Set the DataTypeServices for this parameter
146      *
147      * @param descriptor The DataTypeServices to set for this parameter
148      */

149
150     public void setType(DataTypeDescriptor descriptor) throws StandardException
151     {
152         if (SanityManager.DEBUG)
153         SanityManager.ASSERT(typeServices != null,
154             "typeServices not initialized");
155
156         /* Make sure the type is nullable. */
157         if ( ! descriptor.isNullable())
158         {
159             /*
160             ** Generate a new descriptor with all the same properties as
161             ** the given one, except that it is nullable.
162             */

163             descriptor = new DataTypeDescriptor(descriptor, true);
164         }
165
166         typeServices[parameterNumber] = descriptor;
167
168         //make sure we are calling super's setType. We will get into
169
//an infinite loop if this setType ends up calling the local
170
//setType method
171
super.setType(descriptor);
172
173         if ( getJSQLType() == null ) { setJSQLType( new JSQLType( descriptor ) ); }
174     }
175
176     /**
177      * Mark this as a return output parameter (e.g.
178      * ? = CALL myMethod())
179      */

180     public void setReturnOutputParam(ValueNode valueNode)
181     {
182         returnOutputParameter = valueNode;
183     }
184
185     /**
186      * Is this as a return output parameter (e.g.
187      * ? = CALL myMethod())
188      *
189      * @return true if it is a return param
190      */

191     public boolean isReturnOutputParam()
192     {
193         return returnOutputParameter != null;
194     }
195
196     /**
197      * Bind this expression. A parameter can't figure out what its type
198      * is without knowing where it appears, so this method does nothing.
199      * It is up to the node that points to this parameter node to figure
200      * out the type of the parameter and set it, using the setType()
201      * method above.
202      *
203      * @param fromList The FROM list for the query this
204      * expression is in, for binding columns.
205      * @param subqueryList The subquery list being built as we find SubqueryNodes
206      * @param aggregateVector The aggregate vector being built as we find AggregateNodes
207      *
208      * @return The new top of the expression tree.
209      *
210      * @exception StandardException Thrown on error
211      */

212
213     public ValueNode bindExpression(
214             FromList fromList, SubqueryList subqueryList,
215             Vector JavaDoc aggregateVector)
216                 throws StandardException
217     {
218         checkReliability( "?", CompilerContext.UNNAMED_PARAMETER_ILLEGAL );
219
220         return this;
221     }
222
223     /**
224      * Return whether or not this expression tree represents a constant expression.
225      *
226      * @return Whether or not this expression tree represents a constant expression.
227      */

228     public boolean isConstantExpression()
229     {
230         return true;
231     }
232
233     /** @see ValueNode#constantExpression */
234     public boolean constantExpression(PredicateList whereClause)
235     {
236         return true;
237     }
238
239     /**
240      * Return the variant type for the underlying expression.
241      * The variant type can be:
242      * VARIANT - variant within a scan
243      * (method calls and non-static field access)
244      * SCAN_INVARIANT - invariant within a scan
245      * (column references from outer tables)
246      * QUERY_INVARIANT - invariant within the life of a query
247      * (constant expressions)
248      *
249      * @return The variant type for the underlying expression.
250      */

251     protected int getOrderableVariantType()
252     {
253         // Parameters are invariant for the life of the query
254
return orderableVariantType;
255     }
256
257     /**
258      * In a special circumstance, we want to consider
259      * parameters as constants. For that situation, we
260      * allow a caller to temporarily set us to CONSTANT
261      * and then restore us.
262      */

263     void setOrderableVariantType(int type)
264     {
265         orderableVariantType = type;
266     }
267
268     ////////////////////////////////////////////////////////////////////////
269
//
270
// OVERRIDE METHODS IN VALUE NODE THAT ARE USED WHILE BINDING REPLICATED
271
// CALL WORK STATEMENTS.
272
//
273
// In this scenario, a JSQLType was replicated along with this parameter.
274
// The JSQLType represents the bind() decision of the remote system, which
275
// we want to reproduce locally.
276
//
277
////////////////////////////////////////////////////////////////////////
278

279     /**
280       * Set the JSQLType of this parameter. This supports the unnamed parameters
281       * that we use for replicated work units.
282       *
283       * @param type the JSQLType associated with this parameter
284       */

285     public void setJSQLType
286     (
287         JSQLType type
288     )
289     { jsqlType = type; }
290
291     /**
292       * Get the JSQLType associated with this parameter. Again, part of method
293       * resolution for replicated work units.
294       *
295       * @return the JSQLType that the remote system assigned
296       */

297     public JSQLType getJSQLType()
298     {
299         return jsqlType;
300     }
301
302
303     ////////////////////////////////////////////////////////////////////
304
//
305
// CODE GENERATOR
306
//
307
////////////////////////////////////////////////////////////////////
308

309     /**
310      * For a ParameterNode, we generate for the return value:
311      *
312      * (<java type name>)
313      * ( (BaseActivation) this.getParameter(parameterNumber) )
314      *
315      *
316      * @param acb The ExpressionClassBuilder for the class being built
317      * @param mb The method the expression will go into
318      *
319      *
320      * @exception StandardException Thrown on error
321      */

322     public void generateExpression(ExpressionClassBuilder acb,
323                                             MethodBuilder mb)
324                                     throws StandardException
325     {
326         DataTypeDescriptor dtd = getTypeServices();
327         if ((dtd != null) && dtd.getTypeId().isXMLTypeId()) {
328         // We're a parameter that corresponds to an XML column/target,
329
// which we don't allow. We throw the error here instead of
330
// in "bindExpression" because at the time of bindExpression,
331
// we don't know yet what the type is going to be (only when
332
// the node that points to this parameter calls
333
// "setType" do we figure out the type).
334
throw StandardException.newException(
335                 SQLState.LANG_ATTEMPT_TO_BIND_XML);
336         }
337
338         /* Generate the return value */
339
340         mb.pushThis();
341         mb.push(parameterNumber); // arg
342

343         mb.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation, "getParameter",
344                       ClassName.DataValueDescriptor, 1);
345
346         // For some types perform host variable checking
347
// to match DB2/JCC where if a host variable is too
348
// big it is not accepted, regardless of any trailing padding.
349

350         switch (dtd.getJDBCTypeId()) {
351         case Types.BINARY:
352         case Types.VARBINARY:
353         case Types.LONGVARBINARY:
354         case Types.BLOB:
355             mb.dup();
356             mb.push(dtd.getMaximumWidth());
357             mb.callMethod(VMOpcode.INVOKEINTERFACE, (String JavaDoc) null, "checkHostVariable",
358                       "void", 1);
359             break;
360
361         default:
362             break;
363         }
364
365         /* Cast the result to its specific interface */
366         mb.cast(getTypeCompiler().interfaceName());
367     } // End of generateExpression
368

369     public TypeId getTypeId() throws StandardException
370     {
371         return (returnOutputParameter != null) ?
372             returnOutputParameter.getTypeId() : super.getTypeId();
373     }
374
375     ////////////////////////////////////////////////////////////////////
376
//
377
// STATIC ROUTINES
378
//
379
////////////////////////////////////////////////////////////////////
380

381     /**
382      * Generate the code to create the ParameterValueSet, if necessary,
383      * when constructing the activation. Also generate the code to call
384      * a method that will throw an exception if we try to execute without
385      * all the parameters being set.
386      *
387      * This generated code goes into the Activation's constructor early on.
388      *
389      * @param acb The ExpressionClassBuilder for the class we're building
390      * @param numberOfParameters number of parameters for this statement
391      * @param parameterList The parameter list for the statement.
392      *
393      * @exception StandardException on error
394      */

395     static public void generateParameterValueSet(ExpressionClassBuilder acb,
396                                    int numberOfParameters,
397                                    Vector JavaDoc parameterList)
398         throws StandardException
399     {
400         if (numberOfParameters > 0)
401         {
402             MethodBuilder constructor = acb.getConstructor();
403
404             /*
405             ** Check the first parameter to see if it is a return
406             ** parameter.
407             */

408             boolean hasReturnParam = ((ParameterNode)parameterList.elementAt(0)).isReturnOutputParam();
409
410             /*
411             ** Generate the following:
412             **
413             ** pvs =
414             ** getLanguageConnectionContext()
415             ** .getLanguageFactory()
416             ** .getParameterValueSet(numberOfParameters);
417             **
418             ** pvs is a ParameterValueSet that lives in the superclass of
419             ** the activation being generated.
420             */

421
422             constructor.pushThis(); // for the put field down below
423

424             /* Generate the call to getContext */
425             //?X constructor.pushThis();
426
//?Xconstructor.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Activation, "getLanguageConnectionContext",
427
//?X ClassName.LanguageConnectionContext, 0);
428
/*
429             ** Call getLanguageFactory()
430             */

431             //?Xconstructor.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getLanguageFactory",
432
//?X ClassName.LanguageFactory, 0);
433

434             /*
435             ** Call getParameterValueSet(<number of parameters>, <hasReturnParam>)
436             */

437
438             constructor.push(numberOfParameters); // first arg
439
constructor.push(hasReturnParam); // second arg
440

441             constructor.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation,
442                                     "setParameterValueSet", "void", 2);
443
444             //?Xconstructor.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getParameterValueSet",
445
//?X ClassName.ParameterValueSet, 2);
446

447             /* Assign the return from getParameterValueSet() to the field */
448             //?Xconstructor.putField(ClassName.BaseActivation, "pvs", ClassName.ParameterValueSet);
449
//?Xconstructor.endStatement();
450

451             /*
452             ** Add a call to the execute() method to check
453             ** for missing parameters
454             */

455             MethodBuilder executeMethod = acb.getExecuteMethod();
456
457             executeMethod.pushThis();
458             executeMethod.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation, "throwIfMissingParms", "void", 0);
459         }
460     }
461
462     /**
463      * Get the default value for the parameter. Parameters
464      * may get default values for optimization purposes.
465      *
466      * @return the value, may be null
467      */

468     DataValueDescriptor getDefaultValue()
469     {
470         return defaultValue;
471     }
472
473     /**
474      * @see ValueNode#requiresTypeFromContext
475      */

476     public boolean requiresTypeFromContext()
477     {
478         return true;
479     }
480     
481     /**
482      * @see ValueNode#isParameterNode
483      */

484     public boolean isParameterNode()
485     {
486         return true;
487     }
488
489     /**
490      * @inheritDoc
491      */

492     protected boolean isEquivalent(ValueNode o)
493     {
494         return false;
495     }
496 }
497
Popular Tags