--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.ExpressionClassBuilder\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.sql.compile;\r
+\r
+\r
+import org.apache.derby.iapi.services.compiler.ClassBuilder;\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+import org.apache.derby.iapi.services.compiler.JavaFactory;\r
+import org.apache.derby.iapi.services.compiler.LocalField;\r
+import org.apache.derby.iapi.reference.ClassName;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.sql.compile.CompilerContext;\r
+import org.apache.derby.iapi.sql.compile.ExpressionClassBuilderInterface;\r
+\r
+import org.apache.derby.iapi.sql.execute.ResultSetFactory;\r
+import org.apache.derby.iapi.sql.execute.ExecutionFactory;\r
+import org.apache.derby.iapi.sql.execute.ExecIndexRow;\r
+\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.sql.ParameterValueSet;\r
+import org.apache.derby.iapi.sql.Row;\r
+\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+\r
+import org.apache.derby.impl.sql.compile.OrderedColumnList;\r
+import org.apache.derby.impl.sql.compile.ResultColumnList;\r
+import org.apache.derby.impl.sql.execute.IndexColumnOrder;\r
+import org.apache.derby.iapi.store.access.ColumnOrdering;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.types.DataValueFactory;\r
+import org.apache.derby.iapi.types.TypeId;\r
+\r
+import org.apache.derby.iapi.sql.compile.TypeCompiler;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.util.ByteArray;\r
+\r
+import org.apache.derby.iapi.services.loader.ClassFactory;\r
+import org.apache.derby.iapi.services.loader.GeneratedClass;\r
+import org.apache.derby.iapi.services.loader.GeneratedByteCode;\r
+import org.apache.derby.iapi.services.loader.GeneratedMethod;\r
+\r
+import java.lang.reflect.Modifier;\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableArrayHolder;\r
+\r
+import java.io.Serializable;\r
+\r
+/**\r
+ * ExpressionClassBuilder\r
+ * provides an interface to satisfy generation's\r
+ * common tasks in building classes that involve expressions.\r
+ * This is the common superclass of ActivationClassBuilder and\r
+ * FilterClassBuilder. See the documentation on ActivationClassBuilder.\r
+ *\r
+ */\r
+abstract class ExpressionClassBuilder implements ExpressionClassBuilderInterface\r
+{\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // CONSTANTS\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ static final protected String currentDatetimeFieldName = "cdt";\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // STATE\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ protected ClassBuilder cb;\r
+ protected GeneratedClass gc;\r
+ protected int nextExprNum;\r
+ protected int nextNonFastExpr;\r
+ protected int nextFieldNum;\r
+ protected MethodBuilder constructor;\r
+ CompilerContext myCompCtx;\r
+ MethodBuilder executeMethod; // to find it fast\r
+\r
+ protected LocalField cdtField;\r
+\r
+ //protected final JavaFactory javaFac;\r
+\r
+ private String currentRowScanResultSetName;\r
+\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // CONSTRUCTORS\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ * By the time this is done, it has constructed the following class:\r
+ * <pre>\r
+ * public class #className extends #superClass {\r
+ * public #className() { super(); }\r
+ * }\r
+ * </pre>\r
+ *\r
+ * @exception StandardException thrown on failure\r
+ */\r
+ ExpressionClassBuilder (String superClass, String className, CompilerContext cc ) \r
+ throws StandardException\r
+ {\r
+ int modifiers = Modifier.PUBLIC | Modifier.FINAL;\r
+\r
+ myCompCtx = cc;\r
+ JavaFactory javaFac = myCompCtx.getJavaFactory();\r
+\r
+ if ( className == null ) { className = myCompCtx.getUniqueClassName(); }\r
+\r
+ // start the class\r
+ cb = javaFac.newClassBuilder(myCompCtx.getClassFactory(),\r
+ getPackageName(), modifiers,\r
+ className, superClass);\r
+\r
+ beginConstructor();\r
+ }\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // ABSTRACT METHODS TO BE IMPLEMENTED BY CHILDREN\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ * Get the name of the package that the generated class will live in.\r
+ *\r
+ * @return name of package that the generated class will live in.\r
+ */\r
+ abstract String getPackageName();\r
+\r
+ /**\r
+ * Get the number of ExecRows that must be allocated\r
+ *\r
+ * @return number of ExecRows that must be allocated\r
+ *\r
+ * @exception StandardException thrown on failure\r
+ */\r
+ abstract int getRowCount()\r
+ throws StandardException;\r
+\r
+ /**\r
+ * Sets the number of subqueries under this expression\r
+ *\r
+ *\r
+ * @exception StandardException thrown on failure\r
+ */\r
+ abstract void setNumSubqueries()\r
+ throws StandardException;\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // ACCESSORS\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ Return the base class of the activation's hierarchy\r
+ (the subclass of Object).\r
+\r
+ This class is expected to hold methods used by all\r
+ compilation code, such as datatype compilation code,\r
+ e.g. getDataValueFactory.\r
+ */\r
+ abstract String getBaseClassName();\r
+\r
+ MethodBuilder getConstructor() {\r
+ return constructor;\r
+ }\r
+\r
+ ClassBuilder getClassBuilder() {\r
+ return cb;\r
+ }\r
+\r
+ /**\r
+ * Get the execute method in order to add code to it.\r
+ * Added code will be executed for each execution\r
+ * of the activation. StatementNode completes the\r
+ * execute method so that code added by other nodes\r
+ * will be executed before the ResultSet is created\r
+ * using fillResultSet. \r
+ */\r
+ MethodBuilder getExecuteMethod() {\r
+ return executeMethod;\r
+ }\r
+\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // CONSTRUCTOR MANAGEMENT\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ private final void beginConstructor()\r
+ {\r
+ // create a constructor that just calls super. \r
+ MethodBuilder realConstructor =\r
+ cb.newConstructorBuilder(Modifier.PUBLIC);\r
+ realConstructor.callSuper();\r
+ realConstructor.methodReturn();\r
+ realConstructor.complete();\r
+\r
+ constructor = cb.newMethodBuilder(Modifier.PUBLIC, "void", "postConstructor");\r
+ constructor.addThrownException(ClassName.StandardException);\r
+ }\r
+\r
+ /**\r
+ * Finish the constructor by newing the array of Rows and putting a return \r
+ * at the end of it.\r
+ *\r
+ * @exception StandardException thrown on failure\r
+ */\r
+\r
+ void finishConstructor()\r
+ throws StandardException\r
+ {\r
+ int numResultSets;\r
+\r
+ /* Set the number of subqueries */\r
+ setNumSubqueries();\r
+\r
+ numResultSets = getRowCount();\r
+\r
+ /* Generate the new of ExecRow[numResultSets] when there are ResultSets\r
+ * which return Rows.\r
+ */\r
+ if (numResultSets >= 1)\r
+ {\r
+ addNewArrayOfRows(numResultSets);\r
+ }\r
+\r
+ /* Generated code is:\r
+ * return;\r
+ */\r
+ constructor.methodReturn();\r
+ constructor.complete();\r
+ }\r
+\r
+ /**\r
+ * Generate the assignment for row = new ExecRow[numResultSets]\r
+ *\r
+ * @param numResultSets The size of the array.\r
+ */\r
+ private void addNewArrayOfRows(int numResultSets)\r
+ {\r
+ /* Generated code is:\r
+ * row = new ExecRow[numResultSets];\r
+ */\r
+\r
+ constructor.pushThis();\r
+ constructor.pushNewArray(ClassName.ExecRow, numResultSets);\r
+ constructor.putField(ClassName.BaseActivation, "row", ClassName.ExecRow + "[]");\r
+ constructor.endStatement();\r
+ }\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // ADD FIELDS TO GENERATED CLASS\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ * Add a field declaration to the generated class\r
+ * \r
+ * @param modifiers The | of the modifier values such as public, static, etc.\r
+ * @param type The type of the field in java language.\r
+ * @param name The name of the field.\r
+ *\r
+ * @return None.\r
+ */\r
+ LocalField newFieldDeclaration(int modifiers, String type, String name)\r
+ {\r
+ return cb.addField(type, name, modifiers);\r
+ }\r
+\r
+ /**\r
+ * Add an arbitrarily named field to the generated class.\r
+ *\r
+ * This is used to generate fields where the caller doesn't care what\r
+ * the field is named. It is especially useful for generating arbitrary\r
+ * numbers of fields, where the caller doesn't know in advance how many\r
+ * fields will be used. For example, it is used for generating fields\r
+ * to hold intermediate values from expressions.\r
+ *\r
+ * @param modifiers The | of the modifier values such as public, static, etc.\r
+ * @param type The type of the field in java language.\r
+ *\r
+ * @return The name of the new field\r
+ */\r
+\r
+ LocalField newFieldDeclaration(int modifiers, String type)\r
+ {\r
+ return cb.addField(type, newFieldName(), modifiers);\r
+ }\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // ADD FUNCTIONS TO GENERATED CLASS\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ * Activations might have need of internal functions\r
+ * that are not used by the result sets, but by other\r
+ * activation functions. Thus, we make it possible\r
+ * for functions to be generated directly as well\r
+ * as through the newExprFun interface. newExprFun\r
+ * should be used when a static field pointing to the\r
+ * expression function is needed.\r
+ * <p>\r
+ * The generated function will generally have a generated name\r
+ * that can be viewed through the MethodBuilder interface.\r
+ * This name is generated to ensure uniqueness from other\r
+ * function names in the activation class. If you pass in a function\r
+ * name, think carefully about whether it will collide with other names.\r
+ *\r
+ * @param returnType the return type of the function\r
+ * @param modifiers the modifiers on the function\r
+ *\r
+ * @see #newExprFun\r
+ */\r
+ MethodBuilder newGeneratedFun(String returnType, int modifiers) {\r
+\r
+ return newGeneratedFun(returnType, modifiers,\r
+ (String[]) null);\r
+ }\r
+\r
+ MethodBuilder newGeneratedFun(String returnType, \r
+ int modifiers,\r
+ String[] params) {\r
+\r
+ String exprName = "g".concat(Integer.toString(nextNonFastExpr++));\r
+ return newGeneratedFun(exprName, returnType, modifiers,\r
+ params);\r
+\r
+ }\r
+\r
+ private MethodBuilder newGeneratedFun(String exprName, String returnType, \r
+ int modifiers,\r
+ String[] params) {\r
+\r
+\r
+\r
+ //\r
+ // create a new method supplying the given modifiers and return Type\r
+ // Java: #modifiers #returnType #exprName { }\r
+ //\r
+ MethodBuilder exprMethod;\r
+ if (params == null)\r
+ {\r
+ exprMethod = cb.newMethodBuilder(modifiers, returnType, exprName);\r
+ }\r
+ else\r
+ {\r
+ exprMethod = cb.newMethodBuilder(modifiers, returnType, \r
+ exprName, params);\r
+ }\r
+\r
+ //\r
+ // declare it to throw StandardException\r
+ // Java: #modifiers #returnType #exprName throws StandardException { }\r
+ //\r
+ exprMethod.addThrownException(ClassName.StandardException);\r
+\r
+ return exprMethod;\r
+ }\r
+\r
+ /**\r
+ * "ExprFun"s are the "expression functions" that\r
+ * are specific to a given JSQL statement. For example,\r
+ * an ExprFun is generated to evaluate the where clause\r
+ * of a select statement and return a boolean result.\r
+ * <p>\r
+ *\r
+ * All methods return by this are expected to be called\r
+ * via the GeneratedMethod interface. Thus the methods\r
+ * are public and return java.lang.Object.\r
+ * <p>\r
+ * Once the exprfun has been created, the\r
+ * caller will need to add statements to it,\r
+ * minimally a return statement.\r
+ * <p>\r
+ * ExprFuns return Object types, since they\r
+ * are invoked through reflection and thus their\r
+ * return type would get wrapped in an object anyway.\r
+ * For example: return java.lang.Boolean, not boolean.\r
+ */\r
+ MethodBuilder newExprFun()\r
+ {\r
+ // get next generated function \r
+ String exprName = "e".concat(Integer.toString(nextExprNum++));\r
+\r
+ return newGeneratedFun(exprName, "java.lang.Object", Modifier.PUBLIC, (String[]) null);\r
+ }\r
+\r
+ /**\r
+ Push an expression that is a GeneratedMethod reference to the\r
+ passed in method. aka. a "function pointer".\r
+ */\r
+ void pushMethodReference(MethodBuilder mb, MethodBuilder exprMethod) {\r
+\r
+ mb.pushThis(); // instance\r
+ mb.push(exprMethod.getName()); // arg\r
+ mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.GeneratedByteCode,\r
+ "getMethod",\r
+ ClassName.GeneratedMethod,\r
+ 1\r
+ );\r
+ }\r
+\r
+ /**\r
+ * Start a user expression. The difference between a normal expression\r
+ * (returned by newExprFun)\r
+ * and a user expression is that a user expression catches all exceptions\r
+ * (because we don't want random exceptions thrown from user methods to\r
+ * propagate to the rest of the system.\r
+ *\r
+ * @return A new MethodBuilder\r
+ */\r
+ MethodBuilder newUserExprFun() {\r
+\r
+ MethodBuilder mb = newExprFun();\r
+ mb.addThrownException("java.lang.Exception");\r
+ return mb;\r
+ }\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // CURRENT DATE/TIME SUPPORT\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ This utility method returns an expression for CURRENT_DATE.\r
+ Get the expression this way, because the activation needs to \r
+ generate support information for CURRENT_DATE,\r
+ that would otherwise be painful to create manually.\r
+ */\r
+ void getCurrentDateExpression(MethodBuilder mb) {\r
+ // do any needed setup\r
+ LocalField lf = getCurrentSetup();\r
+\r
+ // generated Java:\r
+ // this.cdt.getCurrentDate();\r
+ mb.getField(lf);\r
+ mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, "getCurrentDate", "java.sql.Date", 0);\r
+ }\r
+\r
+ /**\r
+ This utility method returns an expression for CURRENT_TIME.\r
+ Get the expression this way, because the activation needs to \r
+ generate support information for CURRENT_TIME,\r
+ that would otherwise be painful to create manually.\r
+ */\r
+ void getCurrentTimeExpression(MethodBuilder mb) {\r
+ // do any needed setup\r
+ LocalField lf = getCurrentSetup();\r
+\r
+ // generated Java:\r
+ // this.cdt.getCurrentTime();\r
+ mb.getField(lf);\r
+ mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, "getCurrentTime", "java.sql.Time", 0);\r
+ }\r
+\r
+ /**\r
+ This utility method generates an expression for CURRENT_TIMESTAMP.\r
+ Get the expression this way, because the activation needs to \r
+ generate support information for CURRENT_TIMESTAMP,\r
+ that would otherwise be painful to create manually.\r
+ */\r
+ void getCurrentTimestampExpression(MethodBuilder mb) {\r
+ // do any needed setup\r
+ LocalField lf = getCurrentSetup();\r
+\r
+ // generated Java:\r
+ // this.cdt.getCurrentTimestamp();\r
+ mb.getField(lf);\r
+ mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null,\r
+ "getCurrentTimestamp", "java.sql.Timestamp", 0);\r
+ }\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // COLUMN ORDERING\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ These utility methods buffers compilation from the IndexColumnOrder\r
+ class.\r
+\r
+ They create an ordering based on their parameter, stuff that into\r
+ the prepared statement, and then return the entry # for\r
+ use in the generated code.\r
+\r
+ We could write another utility method to generate code to\r
+ turn an entry # back into an object, but so far no-one needs it.\r
+ \r
+ WARNING: this is a crafty method that ASSUMES that \r
+ you want every column in the list ordered, and that every\r
+ column in the list is the entire actual result colunm.\r
+ It is only useful for DISTINCT in select. \r
+ */\r
+ FormatableArrayHolder getColumnOrdering(ResultColumnList rclist)\r
+ {\r
+ IndexColumnOrder[] ordering;\r
+ int numCols = (rclist == null) ? 0 : rclist.size();\r
+ //skip the columns which are not exclusively part of the insert list\r
+ //ie columns with default and autoincrement. These columns will not\r
+ //be part of ordering.\r
+ int numRealCols = 0;\r
+ for (int i=0; i<numCols; i++)\r
+ {\r
+ if (!(rclist.getResultColumn(i+1).isGeneratedForUnmatchedColumnInInsert()))\r
+ numRealCols++;\r
+ }\r
+\r
+ ordering = new IndexColumnOrder[numRealCols];\r
+ for (int i=0, j=0; i<numCols; i++)\r
+ {\r
+ if (!(rclist.getResultColumn(i+1).isGeneratedForUnmatchedColumnInInsert()))\r
+ {\r
+ ordering[j] = new IndexColumnOrder(i);\r
+ j++;\r
+ }\r
+ }\r
+ return new FormatableArrayHolder(ordering);\r
+ }\r
+\r
+ /**\r
+ * Add a column to the existing Ordering list. Takes\r
+ * a column id and only adds it if it isn't in the list.\r
+ *\r
+ *\r
+ * @return the ColumnOrdering array\r
+ */\r
+ FormatableArrayHolder addColumnToOrdering(\r
+ FormatableArrayHolder orderingHolder,\r
+ int columnNum)\r
+ {\r
+ /*\r
+ ** We don't expect a lot of order by columns, so\r
+ ** linear search.\r
+ */\r
+ ColumnOrdering[] ordering = (ColumnOrdering[])orderingHolder.\r
+ getArray(ColumnOrdering.class);\r
+ int length = ordering.length;\r
+ for (int i = 0; i < length; i++)\r
+ {\r
+ if (ordering[i].getColumnId() == columnNum)\r
+ return orderingHolder;\r
+ }\r
+\r
+ /*\r
+ ** Didn't find it. Allocate a bigger array\r
+ ** and add it to the end\r
+ */\r
+ IndexColumnOrder[] newOrdering = new IndexColumnOrder[length+1];\r
+ System.arraycopy(ordering, 0, newOrdering, 0, length);\r
+ newOrdering[length] = new IndexColumnOrder(columnNum);\r
+ \r
+ return new FormatableArrayHolder(newOrdering);\r
+ } \r
+\r
+\r
+ FormatableArrayHolder getColumnOrdering(OrderedColumnList oclist) {\r
+ int numCols = (oclist == null) ? 0 : oclist.size();\r
+\r
+ if (numCols == 0)\r
+ {\r
+ return new FormatableArrayHolder(new IndexColumnOrder[0]);\r
+ }\r
+\r
+ return new FormatableArrayHolder(oclist.getColumnOrdering());\r
+ }\r
+\r
+ int addItem(Object o) \r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if ((o != null) && !(o instanceof Serializable))\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "o (" + o.getClass().getName() +\r
+ ") expected to be instanceof java.io.Serializable");\r
+ }\r
+ }\r
+ return myCompCtx.addSavedObject(o);\r
+ }\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // Caching resuable Expressions\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ * Get/reuse the Expression for getting the DataValueFactory\r
+ */\r
+ private Object getDVF;\r
+ void pushDataValueFactory(MethodBuilder mb)\r
+ {\r
+ // generates:\r
+ // getDataValueFactory()\r
+ //\r
+\r
+ if (getDVF == null) {\r
+ getDVF = mb.describeMethod(VMOpcode.INVOKEVIRTUAL,\r
+ getBaseClassName(),\r
+ "getDataValueFactory",\r
+ ClassName.DataValueFactory);\r
+ }\r
+\r
+ mb.pushThis();\r
+ mb.callMethod(getDVF);\r
+ }\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // RESULT SET SUPPORT\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ This is a utility method to get a common expression --\r
+ "BaseActivation.getResultSetFactory()".\r
+ <p>\r
+ BaseActivation gets the factory from the context and\r
+ caches it for faster retrieval.\r
+ */\r
+ private Object getRSF;\r
+ void pushGetResultSetFactoryExpression(MethodBuilder mb) {\r
+ // generated Java:\r
+ // this.getResultSetFactory()\r
+ //\r
+ if (getRSF == null) {\r
+ getRSF = mb.describeMethod(VMOpcode.INVOKEVIRTUAL, getBaseClassName(),\r
+ "getResultSetFactory",\r
+ ClassName.ResultSetFactory);\r
+ }\r
+ mb.pushThis();\r
+ mb.callMethod(getRSF);\r
+ }\r
+\r
+ /**\r
+ This is a utility method to get a common expression --\r
+ "BaseActivation.getExecutionFactory()".\r
+ REVISIT: could the same expression objects be reused within\r
+ the tree and have the correct java generated each time?\r
+ <p>\r
+ BaseActivation gets the factory from the context and\r
+ caches it for faster retrieval. \r
+ */\r
+ private Object getEF;\r
+ void pushGetExecutionFactoryExpression(MethodBuilder mb) {\r
+ if (getEF == null) {\r
+ getEF = mb.describeMethod(VMOpcode.INVOKEVIRTUAL, getBaseClassName(),\r
+ "getExecutionFactory",\r
+ ClassName.ExecutionFactory);\r
+ }\r
+\r
+ // generated Java:\r
+ // this.getExecutionFactory()\r
+ //\r
+ mb.pushThis();\r
+ mb.callMethod(getEF);\r
+ }\r
+\r
+ /**\r
+ * Generate a reference to the row array that\r
+ * all activations use.\r
+ * \r
+ * @param eb the expression block\r
+ *\r
+ * @return expression\r
+ */\r
+ //private void pushRowArrayReference(MethodBuilder mb)\r
+ //{ \r
+ // PUSHCOMPILE - cache\r
+ // mb.pushThis();\r
+ // mb.getField(ClassName.BaseActivation, "row", ClassName.ExecRow + "[]");\r
+ //}\r
+\r
+ /**\r
+ * Generate a reference to a colunm in a result set.\r
+ * \r
+ * @param rsNumber the result set number\r
+ * @param colId the column number\r
+ */\r
+ void pushColumnReference(MethodBuilder mb, int rsNumber, int colId)\r
+ {\r
+ mb.pushThis();\r
+ mb.push(rsNumber);\r
+ mb.push(colId);\r
+ mb.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation, "getColumnFromRow",\r
+ ClassName.DataValueDescriptor, 2);\r
+\r
+ //System.out.println("pushColumnReference ");\r
+ //pushRowArrayReference(mb);\r
+ //mb.getArrayElement(rsNumber); // instance for getColumn\r
+ //mb.push(colId); // first arg\r
+ //mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "getColumn", ClassName.DataValueDescriptor, 1);\r
+ }\r
+\r
+ /**\r
+ * Generate a reference to the parameter value\r
+ * set that all activations use.\r
+ * \r
+ */\r
+ void pushPVSReference(MethodBuilder mb)\r
+ {\r
+ // PUSHCOMPILER-WASCACHED\r
+ mb.pushThis();\r
+ mb.getField(ClassName.BaseActivation, "pvs", ClassName.ParameterValueSet);\r
+ }\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // CLASS IMPLEMENTATION\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ /*\r
+ The first time a current datetime is needed, create the class\r
+ level support for it.\r
+ */\r
+ protected LocalField getCurrentSetup() {\r
+ if (cdtField != null)\r
+ return cdtField;\r
+\r
+ // generated Java:\r
+ // 1) the field "cdt" is created:\r
+ // private CurrentDatetime cdt;\r
+ cdtField = newFieldDeclaration(\r
+ Modifier.PRIVATE,\r
+ ClassName.CurrentDatetime,\r
+ currentDatetimeFieldName);\r
+\r
+ // 2) the constructor gets a statement to init CurrentDatetime:\r
+ // cdt = new CurrentDatetime();\r
+\r
+ constructor.pushNewStart(ClassName.CurrentDatetime);\r
+ constructor.pushNewComplete(0);\r
+ constructor.setField(cdtField);\r
+\r
+ return cdtField;\r
+ }\r
+\r
+ /**\r
+ * generated the next field name available.\r
+ * these are of the form 'e#', where # is\r
+ * incremented each time.\r
+ * This shares the name space with the expression methods\r
+ * as Java allows names and fields to have the same name.\r
+ * This reduces the number of constant pool entries created\r
+ * for a generated class file.\r
+ */\r
+ private String newFieldName()\r
+ {\r
+ return "e".concat(Integer.toString(nextFieldNum++));\r
+ }\r
+\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // DEBUG\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // DATATYPES\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+ /**\r
+ * Get the TypeCompiler associated with the given TypeId\r
+ *\r
+ * @param typeId The TypeId to get a TypeCompiler for\r
+ *\r
+ * @return The corresponding TypeCompiler\r
+ *\r
+ */\r
+ protected TypeCompiler getTypeCompiler(TypeId typeId)\r
+ {\r
+ return myCompCtx.getTypeCompilerFactory().getTypeCompiler(typeId);\r
+ }\r
+\r
+ ///////////////////////////////////////////////////////////////////////\r
+ //\r
+ // GENERATE BYTE CODE\r
+ //\r
+ ///////////////////////////////////////////////////////////////////////\r
+\r
+ /**\r
+ * Take the generated class, and turn it into an\r
+ * actual class.\r
+ * <p> This method assumes, does not check, that\r
+ * the class and its parts are all complete.\r
+ *\r
+ * @param savedBytes place to save generated bytes.\r
+ * if null, it is ignored\r
+ * @exception StandardException thrown when exception occurs\r
+ */\r
+ GeneratedClass getGeneratedClass(ByteArray savedBytes) throws StandardException {\r
+ if (gc != null) return gc;\r
+\r
+ if (savedBytes != null)\r
+ {\r
+ ByteArray classBytecode = cb.getClassBytecode();\r
+\r
+ // note: be sure to set the length since\r
+ // the class builder allocates the byte array\r
+ // in big chunks\r
+ savedBytes.setBytes(classBytecode.getArray());\r
+ savedBytes.setLength(classBytecode.getLength());\r
+ }\r
+\r
+ gc = cb.getGeneratedClass();\r
+\r
+ return gc; // !! yippee !! here it is...\r
+ }\r
+\r
+ /**\r
+ * Get a "this" expression declared as an Activation.\r
+ * This is the commonly used type of the this expression.\r
+ *\r
+ */\r
+ void pushThisAsActivation(MethodBuilder mb) {\r
+ // PUSHCOMPILER - WASCACHED\r
+ mb.pushThis();\r
+ mb.upCast(ClassName.Activation);\r
+ }\r
+\r
+ /**\r
+ Generate a Null data value.\r
+ Nothing is required on the stack, a SQL null data value\r
+ is pushed.\r
+ */\r
+ void generateNull(MethodBuilder mb, TypeCompiler tc, int collationType) {\r
+ pushDataValueFactory(mb);\r
+ mb.pushNull(tc.interfaceName());\r
+ tc.generateNull(mb, collationType);\r
+ }\r
+\r
+ /**\r
+ Generate a Null data value.\r
+ The express value is required on the stack and will be popped, a SQL null data value\r
+ is pushed.\r
+ */\r
+ void generateNullWithExpress(MethodBuilder mb, TypeCompiler tc, \r
+ int collationType) {\r
+ pushDataValueFactory(mb);\r
+ mb.swap(); // need the dvf as the instance\r
+ mb.cast(tc.interfaceName());\r
+ tc.generateNull(mb, collationType);\r
+ }\r
+\r
+ /**\r
+ Generate a data value.\r
+ The value is to be set in the SQL data value is required\r
+ on the stack and will be popped, a SQL data value\r
+ is pushed.\r
+ */\r
+ void generateDataValue(MethodBuilder mb, TypeCompiler tc, \r
+ int collationType, LocalField field) {\r
+ pushDataValueFactory(mb);\r
+ mb.swap(); // need the dvf as the instance\r
+ tc.generateDataValue(mb, collationType, field);\r
+ }\r
+\r
+ \r
+ /**\r
+ *generates a variable name for the rowscanresultset.\r
+ *This can not be a fixed name because in cases like\r
+ *cascade delete same activation class will be dealing \r
+ * more than one RowScanResultSets for dependent tables.\r
+ */\r
+\r
+ String newRowLocationScanResultSetName()\r
+ {\r
+ currentRowScanResultSetName = newFieldName();\r
+ return currentRowScanResultSetName;\r
+ }\r
+\r
+ // return the Name of ResultSet with the RowLocations to be modified (deleted or updated).\r
+ String getRowLocationScanResultSetName()\r
+ {\r
+ return currentRowScanResultSetName;\r
+ }\r
+\r
+ \r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r