📄 expressionclassbuilder.java
字号:
} /////////////////////////////////////////////////////////////////////// // // CURRENT DATE/TIME SUPPORT // /////////////////////////////////////////////////////////////////////// /** This utility method returns an expression for CURRENT_DATE. Get the expression this way, because the activation needs to generate support information for CURRENT_DATE, that would otherwise be painful to create manually. */ public void getCurrentDateExpression(MethodBuilder mb) { // do any needed setup LocalField lf = getCurrentSetup(); // generated Java: // this.cdt.getCurrentDate(); mb.getField(lf); mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, "getCurrentDate", "java.sql.Date", 0); } /** This utility method returns an expression for CURRENT_TIME. Get the expression this way, because the activation needs to generate support information for CURRENT_TIME, that would otherwise be painful to create manually. */ public void getCurrentTimeExpression(MethodBuilder mb) { // do any needed setup LocalField lf = getCurrentSetup(); // generated Java: // this.cdt.getCurrentTime(); mb.getField(lf); mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, "getCurrentTime", "java.sql.Time", 0); } /** This utility method generates an expression for CURRENT_TIMESTAMP. Get the expression this way, because the activation needs to generate support information for CURRENT_TIMESTAMP, that would otherwise be painful to create manually. */ public void getCurrentTimestampExpression(MethodBuilder mb) { // do any needed setup LocalField lf = getCurrentSetup(); // generated Java: // this.cdt.getCurrentTimestamp(); mb.getField(lf); mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, "getCurrentTimestamp", "java.sql.Timestamp", 0); } /////////////////////////////////////////////////////////////////////// // // COLUMN ORDERING // /////////////////////////////////////////////////////////////////////// /** These utility methods buffers compilation from the IndexColumnOrder class. They create an ordering based on their parameter, stuff that into the prepared statement, and then return the entry # for use in the generated code. We could write another utility method to generate code to turn an entry # back into an object, but so far no-one needs it. WARNING: this is a crafty method that ASSUMES that you want every column in the list ordered, and that every column in the list is the entire actual result colunm. It is only useful for DISTINCT in select. */ public FormatableArrayHolder getColumnOrdering(ResultColumnList rclist) { IndexColumnOrder[] ordering; int numCols = (rclist == null) ? 0 : rclist.size(); //skip the columns which are not exclusively part of the insert list //ie columns with default and autoincrement. These columns will not //be part of ordering. int numRealCols = 0; for (int i=0; i<numCols; i++) { if (!(rclist.getResultColumn(i+1).isGeneratedForUnmatchedColumnInInsert())) numRealCols++; } ordering = new IndexColumnOrder[numRealCols]; for (int i=0, j=0; i<numCols; i++) { if (!(rclist.getResultColumn(i+1).isGeneratedForUnmatchedColumnInInsert())) { ordering[j] = new IndexColumnOrder(i); j++; } } return new FormatableArrayHolder(ordering); } /** * Add a column to the existing Ordering list. Takes * a column id and only adds it if it isn't in the list. * * @param columNum the column to add * * @return the ColumnOrdering array */ public FormatableArrayHolder addColumnToOrdering( FormatableArrayHolder orderingHolder, int columnNum) { /* ** We don't expect a lot of order by columns, so ** linear search. */ ColumnOrdering[] ordering = (ColumnOrdering[])orderingHolder. getArray(ColumnOrdering.class); int length = ordering.length; for (int i = 0; i < length; i++) { if (ordering[i].getColumnId() == columnNum) return orderingHolder; } /* ** Didn't find it. Allocate a bigger array ** and add it to the end */ IndexColumnOrder[] newOrdering = new IndexColumnOrder[length+1]; System.arraycopy(ordering, 0, newOrdering, 0, length); newOrdering[length] = new IndexColumnOrder(columnNum); return new FormatableArrayHolder(newOrdering); } public FormatableArrayHolder getColumnOrdering(OrderedColumnList oclist) { int numCols = (oclist == null) ? 0 : oclist.size(); if (numCols == 0) { return new FormatableArrayHolder(new IndexColumnOrder[0]); } return new FormatableArrayHolder(oclist.getColumnOrdering()); } public int addItem(Object o) { if (SanityManager.DEBUG) { if ((o != null) && !(o instanceof Serializable)) { SanityManager.THROWASSERT( "o (" + o.getClass().getName() + ") expected to be instanceof java.io.Serializable"); } } return myCompCtx.addSavedObject(o); } /////////////////////////////////////////////////////////////////////// // // Caching resuable Expressions // /////////////////////////////////////////////////////////////////////// /** * Get/reuse the Expression for getting the DataValueFactory */ private Object getDVF; public void pushDataValueFactory(MethodBuilder mb) { // generates: // getDataValueFactory() // if (getDVF == null) { getDVF = mb.describeMethod(VMOpcode.INVOKEVIRTUAL, getBaseClassName(), "getDataValueFactory", ClassName.DataValueFactory); } mb.pushThis(); mb.callMethod(getDVF); } /////////////////////////////////////////////////////////////////////// // // RESULT SET SUPPORT // /////////////////////////////////////////////////////////////////////// /** This is a utility method to get a common expression -- "BaseActivation.getResultSetFactory()". <p> BaseActivation gets the factory from the context and caches it for faster retrieval. */ private Object getRSF; public void pushGetResultSetFactoryExpression(MethodBuilder mb) { // generated Java: // this.getResultSetFactory() // if (getRSF == null) { getRSF = mb.describeMethod(VMOpcode.INVOKEVIRTUAL, getBaseClassName(), "getResultSetFactory", ClassName.ResultSetFactory); } mb.pushThis(); mb.callMethod(getRSF); } /** This is a utility method to get a common expression -- "BaseActivation.getExecutionFactory()". REVISIT: could the same expression objects be reused within the tree and have the correct java generated each time? <p> BaseActivation gets the factory from the context and caches it for faster retrieval. */ private Object getEF; public void pushGetExecutionFactoryExpression(MethodBuilder mb) { if (getEF == null) { getEF = mb.describeMethod(VMOpcode.INVOKEVIRTUAL, getBaseClassName(), "getExecutionFactory", ClassName.ExecutionFactory); } // generated Java: // this.getExecutionFactory() // mb.pushThis(); mb.callMethod(getEF); } /** This utility method returns the resultSetClosed method reference that the activation wants called when a result set closes, to let it clean up. This will be null if none was needed. REMIND: because ObjectManager returns exceptions on its invoke() method and close() is not supposed to return exceptions, we may want to move this to be something done on open() instead of on close(). Otherwise, we have to do try/catch/THROWASSERT in the close code, which looks unfriendly. */ public void pushResultSetClosedMethodFieldAccess(MethodBuilder mb) { if (resultSetClosedMethod != null) pushMethodReference(mb, resultSetClosedMethod); else mb.pushNull(ClassName.GeneratedMethod); } /** * Generate a reference to the row array that * all activations use. * * @param eb the expression block * * @return expression */ //private void pushRowArrayReference(MethodBuilder mb) //{ // PUSHCOMPILE - cache // mb.pushThis(); // mb.getField(ClassName.BaseActivation, "row", ClassName.ExecRow + "[]"); //} /** * Generate a reference to a colunm in a result set. * * @param eb the expression block * @param rsNumber the result set number * @param colId the column number * * @return expression */ public void pushColumnReference(MethodBuilder mb, int rsNumber, int colId) { mb.pushThis(); mb.push(rsNumber); mb.push(colId); mb.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation, "getColumnFromRow", ClassName.DataValueDescriptor, 2); //System.out.println("pushColumnReference "); //pushRowArrayReference(mb); //mb.getArrayElement(rsNumber); // instance for getColumn //mb.push(colId); // first arg //mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "getColumn", ClassName.DataValueDescriptor, 1); } /** * Generate a reference to the parameter value * set that all activations use. * * @param eb the expression block * * @return expression */ public void pushPVSReference(MethodBuilder mb) { // PUSHCOMPILER-WASCACHED mb.pushThis(); mb.getField(ClassName.BaseActivation, "pvs", ClassName.ParameterValueSet); } /////////////////////////////////////////////////////////////////////// // // CLASS IMPLEMENTATION // /////////////////////////////////////////////////////////////////////// /* The first time a current datetime is needed, create the class level support for it. */ protected LocalField getCurrentSetup() { if (cdtField != null) return cdtField; // generated Java: // 1) the field "cdt" is created: // private CurrentDatetime cdt; cdtField = newFieldDeclaration( Modifier.PRIVATE, ClassName.CurrentDatetime, currentDatetimeFieldName); // 2) the constructor gets a statement to init CurrentDatetime: // cdt = new CurrentDatetime(); constructor.pushNewStart(ClassName.CurrentDatetime); constructor.pushNewComplete(0); constructor.setField(cdtField); return cdtField; } /** * generated the next field name available. * these are of the form 'e#', where # is * incremented each time. * This shares the name space with the expression methods * as Java allows names and fields to have the same name. * This reduces the number of constant pool entries created * for a generated class file. */ private String newFieldName() { return "e".concat(Integer.toString(nextFieldNum++)); } /////////////////////////////////////////////////////////////////////// // // DEBUG // /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // // DATATYPES // /////////////////////////////////////////////////////////////////////// /** * Get the TypeCompiler associated with the given TypeId * * @param typeId The TypeId to get a TypeCompiler for * * @return The corresponding TypeCompiler * */ protected TypeCompiler getTypeCompiler(TypeId typeId) { return myCompCtx.getTypeCompilerFactory().getTypeCompiler(typeId); } /////////////////////////////////////////////////////////////////////// // // GENERATE BYTE CODE // /////////////////////////////////////////////////////////////////////// /** * Take the generated class, and turn it into an * actual class. * <p> This method assumes, does not check, that * the class and its parts are all complete. * * @param savedBytes place to save generated bytes. * if null, it is ignored * @exception StandardException thrown when exception occurs */ public GeneratedClass getGeneratedClass(ByteArray savedBytes) throws StandardException { if (gc != null) return gc; if (savedBytes != null) { ByteArray classBytecode = cb.getClassBytecode(); // note: be sure to set the length since // the class builder allocates the byte array // in big chunks savedBytes.setBytes(classBytecode.getArray()); savedBytes.setLength(classBytecode.getLength()); } gc = cb.getGeneratedClass(); return gc; // !! yippee !! here it is... } /** * Get a "this" expression declared as an Activation. * This is the commonly used type of the this expression. * */ public void pushThisAsActivation(MethodBuilder mb) { // PUSHCOMPILER - WASCACHED mb.pushThis(); mb.upCast(ClassName.Activation); } /** Generate a Null data value. Nothing is required on the stack, a SQL null data value is pushed. */ public void generateNull(MethodBuilder mb, TypeCompiler tc) { pushDataValueFactory(mb); mb.pushNull(tc.interfaceName()); tc.generateNull(mb); } /** Generate a Null data value. The express value is required on the stack and will be popped, a SQL null data value is pushed. */ public void generateNullWithExpress(MethodBuilder mb, TypeCompiler tc) { pushDataValueFactory(mb); mb.swap(); // need the dvf as the instance mb.cast(tc.interfaceName()); tc.generateNull(mb); } /** Generate a data value. The value is to be set in the SQL data value is required on the stack and will be popped, a SQL data value is pushed. */ public void generateDataValue(MethodBuilder mb, TypeCompiler tc, LocalField field) { pushDataValueFactory(mb); mb.swap(); // need the dvf as the instance tc.generateDataValue(mb, field); } /** *generates a variable name for the rowscanresultset. *This can not be a fixed name because in cases like *cascade delete same activation class will be dealing * more than one RowScanResultSets for dependent tables. */ public String newRowLocationScanResultSetName() { currentRowScanResultSetName = newFieldName(); return currentRowScanResultSetName; } // return the Name of ResultSet with the RowLocations to be modified (deleted or updated). public String getRowLocationScanResultSetName() { return currentRowScanResultSetName; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -