001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.ActivationClassBuilder
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.services.compiler.ClassBuilder;
025: import org.apache.derby.iapi.services.compiler.MethodBuilder;
026: import org.apache.derby.iapi.services.compiler.LocalField;
027: import org.apache.derby.iapi.reference.ClassName;
028:
029: import org.apache.derby.iapi.services.sanity.SanityManager;
030:
031: import org.apache.derby.iapi.sql.compile.CompilerContext;
032: import org.apache.derby.iapi.sql.compile.CodeGeneration;
033:
034: import org.apache.derby.iapi.sql.execute.CursorResultSet;
035:
036: import org.apache.derby.iapi.sql.ResultSet;
037:
038: import org.apache.derby.iapi.sql.execute.ExecRow;
039:
040: import org.apache.derby.iapi.types.DataTypeDescriptor;
041: import org.apache.derby.iapi.types.TypeId;
042:
043: import org.apache.derby.iapi.error.StandardException;
044:
045: import org.apache.derby.iapi.services.loader.GeneratedMethod;
046: import org.apache.derby.iapi.services.classfile.VMOpcode;
047:
048: import java.lang.reflect.Modifier;
049:
050: import java.io.PrintWriter;
051:
052: import java.io.File;
053: import java.io.FileOutputStream;
054: import java.io.ByteArrayOutputStream;
055: import java.io.IOException;
056: import java.util.Hashtable;
057:
058: /**
059: * ActivationClassBuilder
060: * provides an interface to satisfy generation's
061: * common tasks in building an activation class,
062: * as well as a repository for the JavaFactory used
063: * to generate the basic language constructs for the methods in the class.
064: * Common tasks include the setting of a static field for each
065: * expression function that gets added, the creation
066: * of the execute method that gets expanded as the query tree
067: * is walked, setting the superclass.
068: * <p>
069: * An activation class is defined for each statement. It has
070: * the following basic layout: TBD
071: * See the document
072: * \\Jeeves\Unversioned Repository 1\Internal Technical Documents\Other\GenAndExec.doc
073: * for details.
074: * <p>
075: * We could also verify methods as they are
076: * added, to have 0 parameters, ...
077: *
078: * @author ames
079: */
080: class ActivationClassBuilder extends ExpressionClassBuilder {
081: ///////////////////////////////////////////////////////////////////////
082: //
083: // CONSTANTS
084: //
085: ///////////////////////////////////////////////////////////////////////
086:
087: ///////////////////////////////////////////////////////////////////////
088: //
089: // STATE
090: //
091: ///////////////////////////////////////////////////////////////////////
092:
093: private LocalField targetResultSetField;
094: private LocalField cursorResultSetField;
095:
096: private MethodBuilder closeActivationMethod;
097:
098: ///////////////////////////////////////////////////////////////////////
099: //
100: // CONSTRUCTOR
101: //
102: ///////////////////////////////////////////////////////////////////////
103:
104: /**
105: * By the time this is done, it has constructed the following class:
106: * <pre>
107: * public class #className extends #superClass {
108: * // public void reset() { return; }
109: * public ResultSet execute() throws StandardException {
110: * throwIfClosed("execute");
111: * // statements must be added here
112: * }
113: * public #className() { super(); }
114: * }
115: * </pre>
116: *
117: * @exception StandardException thrown on failure
118: */
119: ActivationClassBuilder(String super Class, CompilerContext cc)
120: throws StandardException {
121: super (super Class, (String) null, cc);
122: executeMethod = beginExecuteMethod();
123: }
124:
125: ///////////////////////////////////////////////////////////////////////
126: //
127: // ACCESSORS
128: //
129: ///////////////////////////////////////////////////////////////////////
130:
131: /**
132: * Get the package name that this generated class lives in
133: *
134: * @return package name
135: */
136: public String getPackageName() {
137: return CodeGeneration.GENERATED_PACKAGE_PREFIX;
138: }
139:
140: /**
141: The base class for activations is BaseActivation
142: */
143: String getBaseClassName() {
144: return ClassName.BaseActivation;
145: }
146:
147: /**
148: * Get the number of ExecRows to allocate
149: *
150: * @exception StandardException thrown on failure
151: * @return package name
152: */
153: public int getRowCount() throws StandardException {
154: return myCompCtx.getNumResultSets();
155: }
156:
157: /**
158: * Generate the assignment for numSubqueries = x
159: *
160: * @exception StandardException thrown on failure
161: */
162: public void setNumSubqueries() {
163: int numSubqueries = myCompCtx.getNumSubquerys();
164:
165: // If there are no subqueries then
166: // the field is set to the correctly
167: // value (0) by java.
168: if (numSubqueries == 0)
169: return;
170:
171: /* Generated code is:
172: * numSubqueries = x;
173: */
174: constructor.pushThis();
175: constructor.push(numSubqueries);
176: constructor.putField(ClassName.BaseActivation, "numSubqueries",
177: "int");
178: constructor.endStatement();
179: }
180:
181: ///////////////////////////////////////////////////////////////////////
182: //
183: // EXECUTE METHODS
184: //
185: ///////////////////////////////////////////////////////////////////////
186:
187: /**
188: * By the time this is done, it has generated the following code
189: * <pre>
190: * public ResultSet execute() throws StandardException {
191: * throwIfClosed("execute");
192: * // statements must be added here
193: * }
194: * }
195: * </pre>
196: *
197: * @exception StandardException thrown on failure
198: */
199: public MethodBuilder beginExecuteMethod() throws StandardException {
200: // create a reset method that does nothing.
201: // REVISIT: this might better belong in the Activation
202: // superclasses ?? not clear yet what it needs to do.
203:
204: // don't yet need a reset method here. when we do,
205: // it will need to call super.reset() as well as
206: // whatever it does.
207: // mb = cb.newMethodBuilder(
208: // Modifier.PUBLIC, "void", "reset");
209: // mb.addStatement(javaFac.newStatement(
210: // javaFac.newSpecialMethodCall(
211: // thisExpression(),
212: // BaseActivation.CLASS_NAME,
213: // "reset", "void")));
214: // mb.addStatement(javaFac.newReturnStatement());
215: // mb.complete(); // there is nothing else.
216:
217: // This method is an implementation of the interface method
218: // Activation - ResultSet execute()
219:
220: // create an empty execute method
221: MethodBuilder mb = cb.newMethodBuilder(Modifier.PUBLIC,
222: ClassName.ResultSet, "execute");
223: mb.addThrownException(ClassName.StandardException);
224:
225: // put a 'throwIfClosed("execute");' statement into the execute method.
226: mb.pushThis(); // instance
227: mb.push("execute");
228: mb.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation,
229: "throwIfClosed", "void", 1);
230:
231: // call this.startExecution(), so the parent class can know an execution
232: // has begun.
233:
234: mb.pushThis(); // instance
235: mb.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation,
236: "startExecution", "void", 0);
237:
238: return mb;
239: }
240:
241: MethodBuilder startResetMethod() {
242: MethodBuilder mb = cb.newMethodBuilder(Modifier.PUBLIC, "void",
243: "reset");
244:
245: mb.addThrownException(ClassName.StandardException);
246: mb.pushThis();
247: mb.callMethod(VMOpcode.INVOKESPECIAL, ClassName.BaseActivation,
248: "reset", "void", 0);
249:
250: return mb;
251: }
252:
253: /**
254: * An execute method always ends in a return statement, returning
255: * the result set that has been constructed. We want to
256: * do some bookkeeping on that statement, so we generate
257: * the return given the result set.
258:
259: Upon entry the only word on the stack is the result set expression
260: */
261: void finishExecuteMethod(boolean genMarkAsTopNode) {
262:
263: executeMethod.pushThis();
264: executeMethod.getField(ClassName.BaseActivation, "resultSet",
265: ClassName.ResultSet);
266:
267: /* We only call markAsTopResultSet() for selects.
268: * Non-select DML marks the top NoPutResultSet in the constructor.
269: * Needed for closing down resultSet on an error.
270: */
271: if (genMarkAsTopNode) {
272: // dup the result set to leave one for the return and one for this call
273: executeMethod.dup();
274: executeMethod.cast(ClassName.NoPutResultSet);
275: executeMethod.callMethod(VMOpcode.INVOKEINTERFACE,
276: (String) null, "markAsTopResultSet", "void", 0);
277: }
278:
279: /* return resultSet */
280: executeMethod.methodReturn();
281: executeMethod.complete();
282:
283: getClassBuilder().newFieldWithAccessors("getExecutionCount",
284: "setExecutionCount", Modifier.PROTECTED, true, "int");
285:
286: getClassBuilder().newFieldWithAccessors(
287: "getRowCountCheckVector", "setRowCountCheckVector",
288: Modifier.PROTECTED, true, "java.util.Vector");
289:
290: getClassBuilder().newFieldWithAccessors(
291: "getStalePlanCheckInterval",
292: "setStalePlanCheckInterval", Modifier.PROTECTED, true,
293: "int");
294:
295: if (closeActivationMethod != null) {
296: closeActivationMethod.methodReturn();
297: closeActivationMethod.complete();
298: }
299: }
300:
301: ///////////////////////////////////////////////////////////////////////
302: //
303: // CURSOR SUPPORT
304: //
305: ///////////////////////////////////////////////////////////////////////
306:
307: /**
308: * Updatable cursors
309: * need to add a getter method for use in BaseActivation to access
310: * the result set that identifies target rows for a positioned
311: * update or delete.
312: * <p>
313: * The code that is generated is:
314: * <pre><verbatim>
315: * public CursorResultSet getTargetResultSet() {
316: * return targetResultSet;
317: * }
318: *
319: * public CursorResultSet getCursorResultSet() {
320: * return cursorResultSet;
321: * }
322: * </verbatim></pre>
323: *
324: */
325: void addCursorPositionCode() {
326:
327: // the getter
328: // This method is an implementation of the interface method
329: // CursorActivation - CursorResultSet getTargetResultSet()
330: MethodBuilder getter = cb.newMethodBuilder(Modifier.PUBLIC,
331: ClassName.CursorResultSet, "getTargetResultSet");
332:
333: getter.getField(targetResultSetField);
334: getter.methodReturn();
335: getter.complete();
336:
337: // This method is an implementation of the interface method
338: // CursorActivation - CursorResultSet getCursorResultSet()
339:
340: getter = cb.newMethodBuilder(Modifier.PUBLIC,
341: ClassName.CursorResultSet, "getCursorResultSet");
342:
343: getter.getField(cursorResultSetField);
344: getter.methodReturn();
345: getter.complete();
346: }
347:
348: /**
349: * Updatable cursors
350: * need to add a field and its initialization
351: * for use in BaseActivation to access the result set that
352: * identifies target rows for a positioned update or delete.
353: * <p>
354: * The code that is generated is:
355: * <pre><verbatim>
356: * private CursorResultSet targetResultSet;
357: *
358: * </verbatim></pre>
359: *
360: * The expression that is generated is:
361: * <pre><verbatim>
362: * (ResultSet) (targetResultSet = (CursorResultSet) #expression#)
363: * </verbatim></pre>
364: *
365: */
366: void rememberCursorTarget(MethodBuilder mb) {
367:
368: // the field
369: targetResultSetField = cb.addField(ClassName.CursorResultSet,
370: "targetResultSet", Modifier.PRIVATE);
371:
372: mb.cast(ClassName.CursorResultSet);
373: mb.putField(targetResultSetField);
374: mb.cast(ClassName.NoPutResultSet);
375: }
376:
377: /**
378: * Updatable cursors
379: * need to add a field and its initialization
380: * for use in BaseActivation to access the result set that
381: * identifies cursor result rows for a positioned update or delete.
382: * <p>
383: * The code that is generated is:
384: * <pre><verbatim>
385: * private CursorResultSet cursorResultSet;
386: *
387: * </verbatim></pre>
388: *
389: * The expression that is generated is:
390: * <pre><verbatim>
391: * (ResultSet) (cursorResultSet = (CursorResultSet) #expression#)
392: * </verbatim></pre>
393:
394: The expression must be the top stack word when this method is called.
395: *
396: */
397: void rememberCursor(MethodBuilder mb) {
398:
399: // the field
400: cursorResultSetField = cb.addField(ClassName.CursorResultSet,
401: "cursorResultSet", Modifier.PRIVATE);
402:
403: mb.cast(ClassName.CursorResultSet);
404: mb.putField(cursorResultSetField);
405: mb.cast(ClassName.ResultSet);
406: }
407:
408: ///////////////////////////////////////////////////////////////////////
409: //
410: // CURRENT DATE/TIME SUPPORT
411: //
412: ///////////////////////////////////////////////////////////////////////
413:
414: /*
415: The first time a current datetime is needed, create the class
416: level support for it. The first half of the logic is in our parent
417: class.
418: */
419: protected LocalField getCurrentSetup() {
420: if (cdtField != null)
421: return cdtField;
422:
423: LocalField lf = super .getCurrentSetup();
424:
425: // 3) the execute method gets a statement (prior to the return)
426: // to tell cdt to restart:
427: // cdt.forget();
428:
429: executeMethod.getField(lf);
430: executeMethod.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null,
431: "forget", "void", 0);
432:
433: return lf;
434: }
435:
436: MethodBuilder getCloseActivationMethod() {
437:
438: if (closeActivationMethod == null) {
439: closeActivationMethod = cb.newMethodBuilder(
440: Modifier.PUBLIC, "void", "closeActivationAction");
441: closeActivationMethod
442: .addThrownException("java.lang.Exception");
443: }
444: return closeActivationMethod;
445: }
446: }
|