Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/derby/impl/sql/compile/ActivationClassBuilder.java


1   /*
2   
3      Derby - Class org.apache.derby.impl.sql.compile.ActivationClassBuilder
4   
5      Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable.
6   
7      Licensed under the Apache License, Version 2.0 (the "License");
8      you may not use this file except in compliance with the License.
9      You may obtain a copy of the License at
10  
11        http://www.apache.org/licenses/LICENSE-2.0
12  
13     Unless required by applicable law or agreed to in writing, software
14     distributed under the License is distributed on an "AS IS" BASIS,
15     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16     See the License for the specific language governing permissions and
17     limitations under the License.
18  
19   */
20  
21  package org.apache.derby.impl.sql.compile;
22  
23  import org.apache.derby.iapi.services.compiler.ClassBuilder;
24  import org.apache.derby.iapi.services.compiler.MethodBuilder;
25  import org.apache.derby.iapi.services.compiler.LocalField;
26  import org.apache.derby.iapi.reference.ClassName;
27  
28  
29  import org.apache.derby.iapi.services.sanity.SanityManager;
30  
31  import org.apache.derby.iapi.sql.compile.CompilerContext;
32  import org.apache.derby.iapi.sql.compile.CodeGeneration;
33  
34  import org.apache.derby.iapi.sql.execute.CursorResultSet;
35  
36  import org.apache.derby.iapi.sql.ResultSet;
37  
38  import org.apache.derby.iapi.sql.execute.ExecRow;
39  
40  import org.apache.derby.iapi.types.DataTypeDescriptor;
41  import org.apache.derby.iapi.types.TypeId;
42  
43  import org.apache.derby.iapi.error.StandardException;
44  
45  import org.apache.derby.iapi.services.loader.GeneratedMethod;
46  import org.apache.derby.iapi.services.classfile.VMOpcode;
47  
48  import java.lang.reflect.Modifier;
49  
50  import java.io.PrintWriter;
51  
52  import java.io.File;
53  import java.io.FileOutputStream;
54  import java.io.ByteArrayOutputStream;
55  import java.io.IOException;
56  import java.util.Hashtable;
57  
58  /**
59   * ActivationClassBuilder
60   * provides an interface to satisfy generation's
61   * common tasks in building an activation class,
62   * as well as a repository for the JavaFactory used
63   * to generate the basic language constructs for the methods in the class.
64   * Common tasks include the setting of a static field for each
65   * expression function that gets added, the creation
66   * of the execute method that gets expanded as the query tree
67   * is walked, setting the superclass.
68   * <p>
69   * An activation class is defined for each statement. It has
70   * the following basic layout: TBD
71   * See the document
72   * \\Jeeves\Unversioned Repository 1\Internal Technical Documents\Other\GenAndExec.doc
73   * for details.
74   * <p>
75   * We could also verify methods as they are
76   * added, to have 0 parameters, ...
77   *
78   * @author ames
79   */
80  public class ActivationClassBuilder  extends  ExpressionClassBuilder
81  {
82    ///////////////////////////////////////////////////////////////////////
83    //
84    // CONSTANTS
85    //
86    ///////////////////////////////////////////////////////////////////////
87  
88    ///////////////////////////////////////////////////////////////////////
89    //
90    // STATE
91    //
92    ///////////////////////////////////////////////////////////////////////
93  
94    private LocalField  targetResultSetField;
95    private LocalField  cursorResultSetField;
96  
97    private MethodBuilder closeActivationMethod;
98  
99  
100   ///////////////////////////////////////////////////////////////////////
101   //
102   // CONSTRUCTOR
103   //
104   ///////////////////////////////////////////////////////////////////////
105 
106   /**
107    * By the time this is done, it has constructed the following class:
108    * <pre>
109    *    public class #className extends #superClass {
110    *    // public void reset() { return; }
111    *    public ResultSet execute() throws StandardException {
112    *      throwIfClosed("execute");
113    *      // statements must be added here
114    *    }
115    *    public #className() { super(); }
116    *    }
117    * </pre>
118    *
119    * @exception StandardException thrown on failure
120    */
121   public ActivationClassBuilder (String superClass, CompilerContext cc) throws StandardException
122   {
123     super( superClass, (String) null, cc );
124     executeMethod = beginExecuteMethod();
125   }
126 
127   ///////////////////////////////////////////////////////////////////////
128   //
129   // ACCESSORS
130   //
131   ///////////////////////////////////////////////////////////////////////
132 
133   /**
134     *  Get the package name that this generated class lives in
135     *
136     *  @return  package name
137     */
138     public  String  getPackageName()
139   {  return  CodeGeneration.GENERATED_PACKAGE_PREFIX; }
140 
141   /**
142     The base class for activations is BaseActivation
143    */
144   public String getBaseClassName() {
145       return ClassName.BaseActivation;
146   }
147 
148 
149   /**
150     *  Get the number of ExecRows to allocate
151     *
152     * @exception StandardException thrown on failure
153     *  @return  package name
154     */
155   public  int    getRowCount()
156      throws StandardException
157   {
158     return  myCompCtx.getNumResultSets();
159   }
160 
161   /**
162    * Generate the assignment for numSubqueries = x
163    *
164    * @param numSubqueries    The number of subqueries in the query.
165    *
166    * @return Nothing.
167    * @exception StandardException thrown on failure
168    */
169   public   void  setNumSubqueries()
170   {
171     int        numSubqueries = myCompCtx.getNumSubquerys();
172 
173     // If there are no subqueries then
174     // the field is set to the correctly
175     // value (0) by java.
176     if (numSubqueries == 0)
177       return;
178 
179     /* Generated code is:
180      *    numSubqueries = x;
181      */
182     constructor.pushThis();
183     constructor.push(numSubqueries);
184     constructor.putField(ClassName.BaseActivation, "numSubqueries", "int");
185     constructor.endStatement();
186   }
187 
188 
189   ///////////////////////////////////////////////////////////////////////
190   //
191   // EXECUTE METHODS
192   //
193   ///////////////////////////////////////////////////////////////////////
194 
195   /**
196    * By the time this is done, it has generated the following code
197    * <pre>
198    *    public ResultSet execute() throws StandardException {
199    *      throwIfClosed("execute");
200    *      // statements must be added here
201    *    }
202    *    }
203    * </pre>
204    *
205    * @exception StandardException thrown on failure
206    */
207   public  MethodBuilder  beginExecuteMethod()
208     throws StandardException
209   {
210     // create a reset method that does nothing.
211     // REVISIT: this might better belong in the Activation
212     // superclasses ?? not clear yet what it needs to do.
213 
214     // don't yet need a reset method here. when we do,
215     // it will need to call super.reset() as well as
216     // whatever it does.
217     // mb = cb.newMethodBuilder(
218     //   Modifier.PUBLIC, "void", "reset");
219     // mb.addStatement(javaFac.newStatement(
220     //    javaFac.newSpecialMethodCall(
221     //      thisExpression(),
222     //      BaseActivation.CLASS_NAME,
223     //      "reset", "void")));
224     // mb.addStatement(javaFac.newReturnStatement());
225     // mb.complete(); // there is nothing else.
226 
227 
228     // This method is an implementation of the interface method
229     // Activation - ResultSet execute()
230 
231     // create an empty execute method
232     MethodBuilder mb = cb.newMethodBuilder(Modifier.PUBLIC,
233       ClassName.ResultSet, "execute");
234     mb.addThrownException(ClassName.StandardException);
235 
236     // put a 'throwIfClosed("execute");' statement into the execute method.
237     mb.pushThis(); // instance
238     mb.push("execute");
239     mb.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation, "throwIfClosed", "void", 1);
240 
241     // call this.startExecution(), so the parent class can know an execution
242     // has begun.
243 
244     mb.pushThis(); // instance
245     mb.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation, "startExecution", "void", 0);
246 
247     return  mb;
248   }
249 
250   public MethodBuilder startResetMethod() {
251     MethodBuilder mb = cb.newMethodBuilder(Modifier.PUBLIC,
252       "void", "reset");
253 
254     mb.addThrownException(ClassName.StandardException);
255     mb.pushThis();
256     mb.callMethod(VMOpcode.INVOKESPECIAL, ClassName.BaseActivation, "reset", "void", 0);
257 
258 
259     return mb;
260   }
261 
262   /**
263    * An execute method always ends in a return statement, returning
264    * the result set that has been constructed.  We want to
265    * do some bookkeeping on that statement, so we generate
266    * the return given the result set.
267 
268      Upon entry the only word on the stack is the result set expression
269    */
270   public void finishExecuteMethod(boolean genMarkAsTopNode) {
271 
272     executeMethod.pushThis();
273     executeMethod.getField(ClassName.BaseActivation, "resultSet", ClassName.ResultSet);
274 
275     /* We only call markAsTopResultSet() for selects.
276      * Non-select DML marks the top NoPutResultSet in the constructor.
277      * Needed for closing down resultSet on an error.
278      */
279     if (genMarkAsTopNode)
280     {
281       // dup the result set to leave one for the return and one for this call
282       executeMethod.dup();
283       executeMethod.cast(ClassName.NoPutResultSet);
284       executeMethod.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "markAsTopResultSet", "void", 0);
285     }
286 
287     /* return resultSet */
288     executeMethod.methodReturn();
289     executeMethod.complete();
290 
291     getClassBuilder().newFieldWithAccessors("getExecutionCount", "setExecutionCount",
292       Modifier.PROTECTED, true, "int");
293 
294     getClassBuilder().newFieldWithAccessors("getRowCountCheckVector", "setRowCountCheckVector",
295       Modifier.PROTECTED, true, "java.util.Vector");
296 
297     getClassBuilder().newFieldWithAccessors("getStalePlanCheckInterval", "setStalePlanCheckInterval",
298       Modifier.PROTECTED, true, "int");
299 
300     if (closeActivationMethod != null) {
301       closeActivationMethod.methodReturn();
302       closeActivationMethod.complete();
303     }
304   }
305 
306   ///////////////////////////////////////////////////////////////////////
307   //
308   // CURSOR SUPPORT
309   //
310   ///////////////////////////////////////////////////////////////////////
311 
312   /**
313    * Updatable cursors
314    * need to add a getter method for use in BaseActivation to access
315    * the result set that identifies target rows for a positioned
316    * update or delete.
317    * <p>
318    * The code that is generated is:
319    * <pre><verbatim>
320    *  public CursorResultSet getTargetResultSet() {
321    *      return targetResultSet;
322    *  }
323    *
324    *  public CursorResultSet getCursorResultSet() {
325    *    return cursorResultSet;
326    *  }
327    * </verbatim></pre>
328    *
329    */
330   public void addCursorPositionCode() {
331 
332     // the getter
333     // This method is an implementation of the interface method
334     // CursorActivation - CursorResultSet getTargetResultSet()
335     MethodBuilder getter = cb.newMethodBuilder(Modifier.PUBLIC, 
336       ClassName.CursorResultSet, "getTargetResultSet");
337 
338     getter.getField(targetResultSetField);
339     getter.methodReturn();
340     getter.complete();
341 
342     // This method is an implementation of the interface method
343     // CursorActivation - CursorResultSet getCursorResultSet()
344 
345     getter = cb.newMethodBuilder(Modifier.PUBLIC, 
346       ClassName.CursorResultSet, "getCursorResultSet");
347 
348     getter.getField(cursorResultSetField);
349     getter.methodReturn();
350     getter.complete();
351   }
352 
353   /**
354    * Updatable cursors
355    * need to add a field and its initialization
356    * for use in BaseActivation to access the result set that
357    * identifies target rows for a positioned update or delete.
358    * <p>
359    * The code that is generated is:
360    * <pre><verbatim>
361    *  private CursorResultSet targetResultSet;
362    *
363    * </verbatim></pre>
364    *
365    * The expression that is generated is:
366    * <pre><verbatim>
367    *  (ResultSet) (targetResultSet = (CursorResultSet) #expression#)
368    * </verbatim></pre>
369    *
370    */
371   public void rememberCursorTarget(MethodBuilder mb) {
372 
373     // the field
374     targetResultSetField = cb.addField(ClassName.CursorResultSet,
375           "targetResultSet",
376           Modifier.PRIVATE);
377 
378     mb.cast(ClassName.CursorResultSet);
379     mb.putField(targetResultSetField);
380     mb.cast(ClassName.NoPutResultSet);
381   }
382 
383   /**
384    * Updatable cursors
385    * need to add a field and its initialization
386    * for use in BaseActivation to access the result set that
387    * identifies cursor result rows for a positioned update or delete.
388    * <p>
389    * The code that is generated is:
390    * <pre><verbatim>
391    *  private CursorResultSet cursorResultSet;
392    *
393    * </verbatim></pre>
394    *
395    * The expression that is generated is:
396    * <pre><verbatim>
397    *  (ResultSet) (cursorResultSet = (CursorResultSet) #expression#)
398    * </verbatim></pre>
399 
400        The expression must be the top stack word when this method is called.
401    *
402    */
403   public void rememberCursor(MethodBuilder mb) {
404 
405     // the field
406     cursorResultSetField = cb.addField(ClassName.CursorResultSet,
407           "cursorResultSet",
408           Modifier.PRIVATE);
409 
410     mb.cast(ClassName.CursorResultSet);
411     mb.putField(cursorResultSetField);
412     mb.cast(ClassName.ResultSet);
413   }
414 
415   ///////////////////////////////////////////////////////////////////////
416   //
417   // CURRENT DATE/TIME SUPPORT
418   //
419   ///////////////////////////////////////////////////////////////////////
420 
421   /*
422     The first time a current datetime is needed, create the class
423     level support for it. The first half of the logic is in our parent
424     class. Then we add logic here to tidy up for ResultSet management.
425    */
426   protected LocalField getCurrentSetup()
427   {
428     if (cdtField != null) return cdtField;
429 
430     LocalField lf = super.getCurrentSetup();
431 
432     // 3) the execute method gets a statement (prior to the return)
433     //    to tell cdt to restart:
434     //    cdt.forget();
435 
436     executeMethod.getField(lf);
437     executeMethod.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, "forget", "void", 0);
438 
439     // 4) a resultSetClosed method is set up to be passed to
440     //    the outermost result set, if it is an open/close result set,
441     //    so that cdt can be told to forget when a result set closes:
442     //    GeneratedMethod rscm; // the name is just a generated name, simpler.
443     //    void rscm() {
444     //    cdt.forget();
445     //    }
446     MethodBuilder mb = newExprFun();
447     mb.getField(lf); // the instance
448     mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, "forget", "void", 0);
449     mb.pushNull("java.lang.Object");
450     mb.methodReturn();
451     mb.complete();
452     
453     resultSetClosedMethod = mb;
454 
455     return lf;
456   }
457 
458   //////////////////////////////////////////////////////////////////////////
459   //
460   //  NAMED PARAMETER METHODS
461   //
462   //////////////////////////////////////////////////////////////////////////
463 
464   /**
465    *  Generates a parameter reference. Only implemented for Filters right now.
466    *
467    *  @param  name    Parameter name.
468    *  @param  position  Parameter id.
469    *  @param  dataType  Parameter datatype.
470    *  @param  mb      The method to put the generated code into
471    *
472    *  @return  an expression representing the parameter reference.
473    *
474    *   @exception StandardException thrown on failure
475    */
476   public  void  getParameterReference( String        name,
477                          int          position,
478                          DataTypeDescriptor    dataType,
479                          MethodBuilder    mb )
480      throws StandardException
481   {
482     if (SanityManager.DEBUG)
483       SanityManager.NOTREACHED();
484   }
485 
486 
487   public MethodBuilder getCloseActivationMethod() {
488 
489     if (closeActivationMethod == null) {
490       closeActivationMethod = cb.newMethodBuilder(Modifier.PUBLIC, "void", "closeActivationAction");
491       closeActivationMethod.addThrownException("java.lang.Exception");
492     }
493     return closeActivationMethod;
494   }
495 }
496