001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.ExpressionClassBuilder
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.JavaFactory;
027: import org.apache.derby.iapi.services.compiler.LocalField;
028: import org.apache.derby.iapi.reference.ClassName;
029:
030: import org.apache.derby.iapi.services.sanity.SanityManager;
031:
032: import org.apache.derby.iapi.sql.compile.CompilerContext;
033: import org.apache.derby.iapi.sql.compile.ExpressionClassBuilderInterface;
034:
035: import org.apache.derby.iapi.sql.execute.ResultSetFactory;
036: import org.apache.derby.iapi.sql.execute.ExecutionFactory;
037: import org.apache.derby.iapi.sql.execute.ExecIndexRow;
038:
039: import org.apache.derby.iapi.sql.Activation;
040: import org.apache.derby.iapi.sql.ParameterValueSet;
041: import org.apache.derby.iapi.sql.Row;
042:
043: import org.apache.derby.iapi.sql.execute.ExecRow;
044:
045: import org.apache.derby.impl.sql.compile.OrderedColumnList;
046: import org.apache.derby.impl.sql.compile.ResultColumnList;
047: import org.apache.derby.impl.sql.execute.IndexColumnOrder;
048: import org.apache.derby.iapi.store.access.ColumnOrdering;
049:
050: import org.apache.derby.iapi.types.DataValueDescriptor;
051: import org.apache.derby.iapi.types.DataTypeDescriptor;
052: import org.apache.derby.iapi.types.DataValueFactory;
053: import org.apache.derby.iapi.types.TypeId;
054:
055: import org.apache.derby.iapi.sql.compile.TypeCompiler;
056:
057: import org.apache.derby.iapi.error.StandardException;
058: import org.apache.derby.iapi.util.ByteArray;
059:
060: import org.apache.derby.iapi.services.loader.ClassFactory;
061: import org.apache.derby.iapi.services.loader.GeneratedClass;
062: import org.apache.derby.iapi.services.loader.GeneratedByteCode;
063: import org.apache.derby.iapi.services.loader.GeneratedMethod;
064:
065: import java.lang.reflect.Modifier;
066: import org.apache.derby.iapi.services.classfile.VMOpcode;
067:
068: import org.apache.derby.iapi.services.monitor.Monitor;
069:
070: import org.apache.derby.iapi.services.io.FormatableArrayHolder;
071:
072: import java.io.Serializable;
073:
074: /**
075: * ExpressionClassBuilder
076: * provides an interface to satisfy generation's
077: * common tasks in building classes that involve expressions.
078: * This is the common superclass of ActivationClassBuilder and
079: * FilterClassBuilder. See the documentation on ActivationClassBuilder.
080: *
081: * @author Rick Extracted out of ActivationClassBuilder
082: */
083: abstract class ExpressionClassBuilder implements
084: ExpressionClassBuilderInterface {
085: ///////////////////////////////////////////////////////////////////////
086: //
087: // CONSTANTS
088: //
089: ///////////////////////////////////////////////////////////////////////
090:
091: static final protected String currentDatetimeFieldName = "cdt";
092:
093: ///////////////////////////////////////////////////////////////////////
094: //
095: // STATE
096: //
097: ///////////////////////////////////////////////////////////////////////
098:
099: protected ClassBuilder cb;
100: protected GeneratedClass gc;
101: protected int nextExprNum;
102: protected int nextNonFastExpr;
103: protected int nextFieldNum;
104: protected MethodBuilder constructor;
105: CompilerContext myCompCtx;
106: MethodBuilder executeMethod; // to find it fast
107:
108: protected LocalField cdtField;
109:
110: //protected final JavaFactory javaFac;
111:
112: private String currentRowScanResultSetName;
113:
114: ///////////////////////////////////////////////////////////////////////
115: //
116: // CONSTRUCTORS
117: //
118: ///////////////////////////////////////////////////////////////////////
119:
120: /**
121: * By the time this is done, it has constructed the following class:
122: * <pre>
123: * public class #className extends #superClass {
124: * public #className() { super(); }
125: * }
126: * </pre>
127: *
128: * @exception StandardException thrown on failure
129: */
130: ExpressionClassBuilder(String super Class, String className,
131: CompilerContext cc) throws StandardException {
132: int modifiers = Modifier.PUBLIC | Modifier.FINAL;
133:
134: myCompCtx = cc;
135: JavaFactory javaFac = myCompCtx.getJavaFactory();
136:
137: if (className == null) {
138: className = myCompCtx.getUniqueClassName();
139: }
140:
141: // start the class
142: cb = javaFac.newClassBuilder(myCompCtx.getClassFactory(),
143: getPackageName(), modifiers, className, super Class);
144:
145: beginConstructor();
146: }
147:
148: ///////////////////////////////////////////////////////////////////////
149: //
150: // ABSTRACT METHODS TO BE IMPLEMENTED BY CHILDREN
151: //
152: ///////////////////////////////////////////////////////////////////////
153:
154: /**
155: * Get the name of the package that the generated class will live in.
156: *
157: * @return name of package that the generated class will live in.
158: */
159: abstract String getPackageName();
160:
161: /**
162: * Get the number of ExecRows that must be allocated
163: *
164: * @return number of ExecRows that must be allocated
165: *
166: * @exception StandardException thrown on failure
167: */
168: abstract int getRowCount() throws StandardException;
169:
170: /**
171: * Sets the number of subqueries under this expression
172: *
173: *
174: * @exception StandardException thrown on failure
175: */
176: abstract void setNumSubqueries() throws StandardException;
177:
178: /**
179: * Build boiler plate for the Execute method
180: *
181: *
182: * @return a method builder containing boiler plate for the Execute method
183: *
184: * @exception StandardException thrown on failure
185: */
186: abstract MethodBuilder beginExecuteMethod()
187: throws StandardException;
188:
189: /**
190: * Finish up the Execute method.
191: *
192: *
193: * @exception StandardException thrown on failure
194: */
195: abstract void finishExecuteMethod(boolean genMarkAsTopNode)
196: throws StandardException;
197:
198: ///////////////////////////////////////////////////////////////////////
199: //
200: // ACCESSORS
201: //
202: ///////////////////////////////////////////////////////////////////////
203:
204: /**
205: Return the base class of the activation's hierarchy
206: (the subclass of Object).
207:
208: This class is expected to hold methods used by all
209: compilation code, such as datatype compilation code,
210: e.g. getDataValueFactory.
211: */
212: abstract String getBaseClassName();
213:
214: MethodBuilder getConstructor() {
215: return constructor;
216: }
217:
218: ClassBuilder getClassBuilder() {
219: return cb;
220: }
221:
222: /**
223: * The execute method returns a result set that will evaluate the
224: * statement this activation class is the compiled form of.
225: * REVISIT: do we need to give the caller the ability to touch it
226: * directly, or could we wrap the alterations to it in this class?
227: */
228: MethodBuilder getExecuteMethod() {
229: return executeMethod;
230: }
231:
232: ///////////////////////////////////////////////////////////////////////
233: //
234: // CONSTRUCTOR MANAGEMENT
235: //
236: ///////////////////////////////////////////////////////////////////////
237:
238: private final void beginConstructor() {
239: // create a constructor that just calls super.
240: MethodBuilder realConstructor = cb
241: .newConstructorBuilder(Modifier.PUBLIC);
242: realConstructor.callSuper();
243: realConstructor.methodReturn();
244: realConstructor.complete();
245:
246: constructor = cb.newMethodBuilder(Modifier.PUBLIC, "void",
247: "postConstructor");
248: constructor.addThrownException(ClassName.StandardException);
249: }
250:
251: /**
252: * Finish the constructor by newing the array of Rows and putting a return
253: * at the end of it.
254: *
255: * @exception StandardException thrown on failure
256: */
257:
258: void finishConstructor() throws StandardException {
259: int numResultSets;
260:
261: /* Set the number of subqueries */
262: setNumSubqueries();
263:
264: numResultSets = getRowCount();
265:
266: /* Generate the new of ExecRow[numResultSets] when there are ResultSets
267: * which return Rows.
268: */
269: if (numResultSets >= 1) {
270: addNewArrayOfRows(numResultSets);
271: }
272:
273: /* Generated code is:
274: * return;
275: */
276: constructor.methodReturn();
277: constructor.complete();
278: }
279:
280: /**
281: * Generate the assignment for row = new ExecRow[numResultSets]
282: *
283: * @param numResultSets The size of the array.
284: */
285: private void addNewArrayOfRows(int numResultSets) {
286: /* Generated code is:
287: * row = new ExecRow[numResultSets];
288: */
289:
290: constructor.pushThis();
291: constructor.pushNewArray(ClassName.ExecRow, numResultSets);
292: constructor.putField(ClassName.BaseActivation, "row",
293: ClassName.ExecRow + "[]");
294: constructor.endStatement();
295: }
296:
297: ///////////////////////////////////////////////////////////////////////
298: //
299: // ADD FIELDS TO GENERATED CLASS
300: //
301: ///////////////////////////////////////////////////////////////////////
302:
303: /**
304: * Add a field declaration to the generated class
305: *
306: * @param modifiers The | of the modifier values such as public, static, etc.
307: * @param type The type of the field in java language.
308: * @param name The name of the field.
309: *
310: * @return None.
311: */
312: LocalField newFieldDeclaration(int modifiers, String type,
313: String name) {
314: return cb.addField(type, name, modifiers);
315: }
316:
317: /**
318: * Add an arbitrarily named field to the generated class.
319: *
320: * This is used to generate fields where the caller doesn't care what
321: * the field is named. It is especially useful for generating arbitrary
322: * numbers of fields, where the caller doesn't know in advance how many
323: * fields will be used. For example, it is used for generating fields
324: * to hold intermediate values from expressions.
325: *
326: * @param modifiers The | of the modifier values such as public, static, etc.
327: * @param type The type of the field in java language.
328: *
329: * @return The name of the new field
330: */
331:
332: LocalField newFieldDeclaration(int modifiers, String type) {
333: return cb.addField(type, newFieldName(), modifiers);
334: }
335:
336: ///////////////////////////////////////////////////////////////////////
337: //
338: // ADD FUNCTIONS TO GENERATED CLASS
339: //
340: ///////////////////////////////////////////////////////////////////////
341:
342: /**
343: * Activations might have need of internal functions
344: * that are not used by the result sets, but by other
345: * activation functions. Thus, we make it possible
346: * for functions to be generated directly as well
347: * as through the newExprFun interface. newExprFun
348: * should be used when a static field pointing to the
349: * expression function is needed.
350: * <p>
351: * The generated function will generally have a generated name
352: * that can be viewed through the MethodBuilder interface.
353: * This name is generated to ensure uniqueness from other
354: * function names in the activation class. If you pass in a function
355: * name, think carefully about whether it will collide with other names.
356: *
357: * @param returnType the return type of the function
358: * @param modifiers the modifiers on the function
359: *
360: * @see #newExprFun
361: */
362: MethodBuilder newGeneratedFun(String returnType, int modifiers) {
363:
364: return newGeneratedFun(returnType, modifiers, (String[]) null);
365: }
366:
367: MethodBuilder newGeneratedFun(String returnType, int modifiers,
368: String[] params) {
369:
370: String exprName = "g".concat(Integer
371: .toString(nextNonFastExpr++));
372: return newGeneratedFun(exprName, returnType, modifiers, params);
373:
374: }
375:
376: private MethodBuilder newGeneratedFun(String exprName,
377: String returnType, int modifiers, String[] params) {
378:
379: //
380: // create a new method supplying the given modifiers and return Type
381: // Java: #modifiers #returnType #exprName { }
382: //
383: MethodBuilder exprMethod;
384: if (params == null) {
385: exprMethod = cb.newMethodBuilder(modifiers, returnType,
386: exprName);
387: } else {
388: exprMethod = cb.newMethodBuilder(modifiers, returnType,
389: exprName, params);
390: }
391:
392: //
393: // declare it to throw StandardException
394: // Java: #modifiers #returnType #exprName throws StandardException { }
395: //
396: exprMethod.addThrownException(ClassName.StandardException);
397:
398: return exprMethod;
399: }
400:
401: /**
402: * "ExprFun"s are the "expression functions" that
403: * are specific to a given JSQL statement. For example,
404: * an ExprFun is generated to evaluate the where clause
405: * of a select statement and return a boolean result.
406: * <p>
407: *
408: * All methods return by this are expected to be called
409: * via the GeneratedMethod interface. Thus the methods
410: * are public and return java.lang.Object.
411: * <p>
412: * Once the exprfun has been created, the
413: * caller will need to add statements to it,
414: * minimally a return statement.
415: * <p>
416: * ExprFuns return Object types, since they
417: * are invoked through reflection and thus their
418: * return type would get wrapped in an object anyway.
419: * For example: return java.lang.Boolean, not boolean.
420: */
421: MethodBuilder newExprFun() {
422: // get next generated function
423: String exprName = "e".concat(Integer.toString(nextExprNum++));
424:
425: return newGeneratedFun(exprName, "java.lang.Object",
426: Modifier.PUBLIC, (String[]) null);
427: }
428:
429: /**
430: Push an expression that is a GeneratedMethod reference to the
431: passed in method. aka. a "function pointer".
432: */
433: void pushMethodReference(MethodBuilder mb, MethodBuilder exprMethod) {
434:
435: mb.pushThis(); // instance
436: mb.push(exprMethod.getName()); // arg
437: mb.callMethod(VMOpcode.INVOKEINTERFACE,
438: ClassName.GeneratedByteCode, "getMethod",
439: ClassName.GeneratedMethod, 1);
440: }
441:
442: /**
443: * Start a user expression. The difference between a normal expression
444: * (returned by newExprFun)
445: * and a user expression is that a user expression catches all exceptions
446: * (because we don't want random exceptions thrown from user methods to
447: * propagate to the rest of the system.
448: *
449: * @return A new MethodBuilder
450: */
451: MethodBuilder newUserExprFun() {
452:
453: MethodBuilder mb = newExprFun();
454: mb.addThrownException("java.lang.Exception");
455: return mb;
456: }
457:
458: ///////////////////////////////////////////////////////////////////////
459: //
460: // CURRENT DATE/TIME SUPPORT
461: //
462: ///////////////////////////////////////////////////////////////////////
463:
464: /**
465: This utility method returns an expression for CURRENT_DATE.
466: Get the expression this way, because the activation needs to
467: generate support information for CURRENT_DATE,
468: that would otherwise be painful to create manually.
469: */
470: void getCurrentDateExpression(MethodBuilder mb) {
471: // do any needed setup
472: LocalField lf = getCurrentSetup();
473:
474: // generated Java:
475: // this.cdt.getCurrentDate();
476: mb.getField(lf);
477: mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null,
478: "getCurrentDate", "java.sql.Date", 0);
479: }
480:
481: /**
482: This utility method returns an expression for CURRENT_TIME.
483: Get the expression this way, because the activation needs to
484: generate support information for CURRENT_TIME,
485: that would otherwise be painful to create manually.
486: */
487: void getCurrentTimeExpression(MethodBuilder mb) {
488: // do any needed setup
489: LocalField lf = getCurrentSetup();
490:
491: // generated Java:
492: // this.cdt.getCurrentTime();
493: mb.getField(lf);
494: mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null,
495: "getCurrentTime", "java.sql.Time", 0);
496: }
497:
498: /**
499: This utility method generates an expression for CURRENT_TIMESTAMP.
500: Get the expression this way, because the activation needs to
501: generate support information for CURRENT_TIMESTAMP,
502: that would otherwise be painful to create manually.
503: */
504: void getCurrentTimestampExpression(MethodBuilder mb) {
505: // do any needed setup
506: LocalField lf = getCurrentSetup();
507:
508: // generated Java:
509: // this.cdt.getCurrentTimestamp();
510: mb.getField(lf);
511: mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null,
512: "getCurrentTimestamp", "java.sql.Timestamp", 0);
513: }
514:
515: ///////////////////////////////////////////////////////////////////////
516: //
517: // COLUMN ORDERING
518: //
519: ///////////////////////////////////////////////////////////////////////
520:
521: /**
522: These utility methods buffers compilation from the IndexColumnOrder
523: class.
524:
525: They create an ordering based on their parameter, stuff that into
526: the prepared statement, and then return the entry # for
527: use in the generated code.
528:
529: We could write another utility method to generate code to
530: turn an entry # back into an object, but so far no-one needs it.
531:
532: WARNING: this is a crafty method that ASSUMES that
533: you want every column in the list ordered, and that every
534: column in the list is the entire actual result colunm.
535: It is only useful for DISTINCT in select.
536: */
537: FormatableArrayHolder getColumnOrdering(ResultColumnList rclist) {
538: IndexColumnOrder[] ordering;
539: int numCols = (rclist == null) ? 0 : rclist.size();
540: //skip the columns which are not exclusively part of the insert list
541: //ie columns with default and autoincrement. These columns will not
542: //be part of ordering.
543: int numRealCols = 0;
544: for (int i = 0; i < numCols; i++) {
545: if (!(rclist.getResultColumn(i + 1)
546: .isGeneratedForUnmatchedColumnInInsert()))
547: numRealCols++;
548: }
549:
550: ordering = new IndexColumnOrder[numRealCols];
551: for (int i = 0, j = 0; i < numCols; i++) {
552: if (!(rclist.getResultColumn(i + 1)
553: .isGeneratedForUnmatchedColumnInInsert())) {
554: ordering[j] = new IndexColumnOrder(i);
555: j++;
556: }
557: }
558: return new FormatableArrayHolder(ordering);
559: }
560:
561: /**
562: * Add a column to the existing Ordering list. Takes
563: * a column id and only adds it if it isn't in the list.
564: *
565: *
566: * @return the ColumnOrdering array
567: */
568: FormatableArrayHolder addColumnToOrdering(
569: FormatableArrayHolder orderingHolder, int columnNum) {
570: /*
571: ** We don't expect a lot of order by columns, so
572: ** linear search.
573: */
574: ColumnOrdering[] ordering = (ColumnOrdering[]) orderingHolder
575: .getArray(ColumnOrdering.class);
576: int length = ordering.length;
577: for (int i = 0; i < length; i++) {
578: if (ordering[i].getColumnId() == columnNum)
579: return orderingHolder;
580: }
581:
582: /*
583: ** Didn't find it. Allocate a bigger array
584: ** and add it to the end
585: */
586: IndexColumnOrder[] newOrdering = new IndexColumnOrder[length + 1];
587: System.arraycopy(ordering, 0, newOrdering, 0, length);
588: newOrdering[length] = new IndexColumnOrder(columnNum);
589:
590: return new FormatableArrayHolder(newOrdering);
591: }
592:
593: FormatableArrayHolder getColumnOrdering(OrderedColumnList oclist) {
594: int numCols = (oclist == null) ? 0 : oclist.size();
595:
596: if (numCols == 0) {
597: return new FormatableArrayHolder(new IndexColumnOrder[0]);
598: }
599:
600: return new FormatableArrayHolder(oclist.getColumnOrdering());
601: }
602:
603: int addItem(Object o) {
604: if (SanityManager.DEBUG) {
605: if ((o != null) && !(o instanceof Serializable)) {
606: SanityManager
607: .THROWASSERT("o ("
608: + o.getClass().getName()
609: + ") expected to be instanceof java.io.Serializable");
610: }
611: }
612: return myCompCtx.addSavedObject(o);
613: }
614:
615: ///////////////////////////////////////////////////////////////////////
616: //
617: // Caching resuable Expressions
618: //
619: ///////////////////////////////////////////////////////////////////////
620:
621: /**
622: * Get/reuse the Expression for getting the DataValueFactory
623: */
624: private Object getDVF;
625:
626: void pushDataValueFactory(MethodBuilder mb) {
627: // generates:
628: // getDataValueFactory()
629: //
630:
631: if (getDVF == null) {
632: getDVF = mb.describeMethod(VMOpcode.INVOKEVIRTUAL,
633: getBaseClassName(), "getDataValueFactory",
634: ClassName.DataValueFactory);
635: }
636:
637: mb.pushThis();
638: mb.callMethod(getDVF);
639: }
640:
641: ///////////////////////////////////////////////////////////////////////
642: //
643: // RESULT SET SUPPORT
644: //
645: ///////////////////////////////////////////////////////////////////////
646:
647: /**
648: This is a utility method to get a common expression --
649: "BaseActivation.getResultSetFactory()".
650: <p>
651: BaseActivation gets the factory from the context and
652: caches it for faster retrieval.
653: */
654: private Object getRSF;
655:
656: void pushGetResultSetFactoryExpression(MethodBuilder mb) {
657: // generated Java:
658: // this.getResultSetFactory()
659: //
660: if (getRSF == null) {
661: getRSF = mb.describeMethod(VMOpcode.INVOKEVIRTUAL,
662: getBaseClassName(), "getResultSetFactory",
663: ClassName.ResultSetFactory);
664: }
665: mb.pushThis();
666: mb.callMethod(getRSF);
667: }
668:
669: /**
670: This is a utility method to get a common expression --
671: "BaseActivation.getExecutionFactory()".
672: REVISIT: could the same expression objects be reused within
673: the tree and have the correct java generated each time?
674: <p>
675: BaseActivation gets the factory from the context and
676: caches it for faster retrieval.
677: */
678: private Object getEF;
679:
680: void pushGetExecutionFactoryExpression(MethodBuilder mb) {
681: if (getEF == null) {
682: getEF = mb.describeMethod(VMOpcode.INVOKEVIRTUAL,
683: getBaseClassName(), "getExecutionFactory",
684: ClassName.ExecutionFactory);
685: }
686:
687: // generated Java:
688: // this.getExecutionFactory()
689: //
690: mb.pushThis();
691: mb.callMethod(getEF);
692: }
693:
694: /**
695: * Generate a reference to the row array that
696: * all activations use.
697: *
698: * @param eb the expression block
699: *
700: * @return expression
701: */
702: //private void pushRowArrayReference(MethodBuilder mb)
703: //{
704: // PUSHCOMPILE - cache
705: // mb.pushThis();
706: // mb.getField(ClassName.BaseActivation, "row", ClassName.ExecRow + "[]");
707: //}
708: /**
709: * Generate a reference to a colunm in a result set.
710: *
711: * @param rsNumber the result set number
712: * @param colId the column number
713: */
714: void pushColumnReference(MethodBuilder mb, int rsNumber, int colId) {
715: mb.pushThis();
716: mb.push(rsNumber);
717: mb.push(colId);
718: mb.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation,
719: "getColumnFromRow", ClassName.DataValueDescriptor, 2);
720:
721: //System.out.println("pushColumnReference ");
722: //pushRowArrayReference(mb);
723: //mb.getArrayElement(rsNumber); // instance for getColumn
724: //mb.push(colId); // first arg
725: //mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "getColumn", ClassName.DataValueDescriptor, 1);
726: }
727:
728: /**
729: * Generate a reference to the parameter value
730: * set that all activations use.
731: *
732: */
733: void pushPVSReference(MethodBuilder mb) {
734: // PUSHCOMPILER-WASCACHED
735: mb.pushThis();
736: mb.getField(ClassName.BaseActivation, "pvs",
737: ClassName.ParameterValueSet);
738: }
739:
740: ///////////////////////////////////////////////////////////////////////
741: //
742: // CLASS IMPLEMENTATION
743: //
744: ///////////////////////////////////////////////////////////////////////
745:
746: /*
747: The first time a current datetime is needed, create the class
748: level support for it.
749: */
750: protected LocalField getCurrentSetup() {
751: if (cdtField != null)
752: return cdtField;
753:
754: // generated Java:
755: // 1) the field "cdt" is created:
756: // private CurrentDatetime cdt;
757: cdtField = newFieldDeclaration(Modifier.PRIVATE,
758: ClassName.CurrentDatetime, currentDatetimeFieldName);
759:
760: // 2) the constructor gets a statement to init CurrentDatetime:
761: // cdt = new CurrentDatetime();
762:
763: constructor.pushNewStart(ClassName.CurrentDatetime);
764: constructor.pushNewComplete(0);
765: constructor.setField(cdtField);
766:
767: return cdtField;
768: }
769:
770: /**
771: * generated the next field name available.
772: * these are of the form 'e#', where # is
773: * incremented each time.
774: * This shares the name space with the expression methods
775: * as Java allows names and fields to have the same name.
776: * This reduces the number of constant pool entries created
777: * for a generated class file.
778: */
779: private String newFieldName() {
780: return "e".concat(Integer.toString(nextFieldNum++));
781: }
782:
783: ///////////////////////////////////////////////////////////////////////
784: //
785: // DEBUG
786: //
787: ///////////////////////////////////////////////////////////////////////
788:
789: ///////////////////////////////////////////////////////////////////////
790: //
791: // DATATYPES
792: //
793: ///////////////////////////////////////////////////////////////////////
794: /**
795: * Get the TypeCompiler associated with the given TypeId
796: *
797: * @param typeId The TypeId to get a TypeCompiler for
798: *
799: * @return The corresponding TypeCompiler
800: *
801: */
802: protected TypeCompiler getTypeCompiler(TypeId typeId) {
803: return myCompCtx.getTypeCompilerFactory().getTypeCompiler(
804: typeId);
805: }
806:
807: ///////////////////////////////////////////////////////////////////////
808: //
809: // GENERATE BYTE CODE
810: //
811: ///////////////////////////////////////////////////////////////////////
812:
813: /**
814: * Take the generated class, and turn it into an
815: * actual class.
816: * <p> This method assumes, does not check, that
817: * the class and its parts are all complete.
818: *
819: * @param savedBytes place to save generated bytes.
820: * if null, it is ignored
821: * @exception StandardException thrown when exception occurs
822: */
823: GeneratedClass getGeneratedClass(ByteArray savedBytes)
824: throws StandardException {
825: if (gc != null)
826: return gc;
827:
828: if (savedBytes != null) {
829: ByteArray classBytecode = cb.getClassBytecode();
830:
831: // note: be sure to set the length since
832: // the class builder allocates the byte array
833: // in big chunks
834: savedBytes.setBytes(classBytecode.getArray());
835: savedBytes.setLength(classBytecode.getLength());
836: }
837:
838: gc = cb.getGeneratedClass();
839:
840: return gc; // !! yippee !! here it is...
841: }
842:
843: /**
844: * Get a "this" expression declared as an Activation.
845: * This is the commonly used type of the this expression.
846: *
847: */
848: void pushThisAsActivation(MethodBuilder mb) {
849: // PUSHCOMPILER - WASCACHED
850: mb.pushThis();
851: mb.upCast(ClassName.Activation);
852: }
853:
854: /**
855: Generate a Null data value.
856: Nothing is required on the stack, a SQL null data value
857: is pushed.
858: */
859: void generateNull(MethodBuilder mb, TypeCompiler tc) {
860: pushDataValueFactory(mb);
861: mb.pushNull(tc.interfaceName());
862: tc.generateNull(mb);
863: }
864:
865: /**
866: Generate a Null data value.
867: The express value is required on the stack and will be popped, a SQL null data value
868: is pushed.
869: */
870: void generateNullWithExpress(MethodBuilder mb, TypeCompiler tc) {
871: pushDataValueFactory(mb);
872: mb.swap(); // need the dvf as the instance
873: mb.cast(tc.interfaceName());
874: tc.generateNull(mb);
875: }
876:
877: /**
878: Generate a data value.
879: The value is to be set in the SQL data value is required
880: on the stack and will be popped, a SQL data value
881: is pushed.
882: */
883: void generateDataValue(MethodBuilder mb, TypeCompiler tc,
884: LocalField field) {
885: pushDataValueFactory(mb);
886: mb.swap(); // need the dvf as the instance
887: tc.generateDataValue(mb, field);
888: }
889:
890: /**
891: *generates a variable name for the rowscanresultset.
892: *This can not be a fixed name because in cases like
893: *cascade delete same activation class will be dealing
894: * more than one RowScanResultSets for dependent tables.
895: */
896:
897: String newRowLocationScanResultSetName() {
898: currentRowScanResultSetName = newFieldName();
899: return currentRowScanResultSetName;
900: }
901:
902: // return the Name of ResultSet with the RowLocations to be modified (deleted or updated).
903: String getRowLocationScanResultSetName() {
904: return currentRowScanResultSetName;
905: }
906:
907: }
|