📄 expressionclassbuilder.java
字号:
/* Derby - Class org.apache.derby.impl.sql.compile.ExpressionClassBuilder Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package org.apache.derby.impl.sql.compile;import org.apache.derby.iapi.services.compiler.ClassBuilder;import org.apache.derby.iapi.services.compiler.MethodBuilder;import org.apache.derby.iapi.services.compiler.JavaFactory;import org.apache.derby.iapi.services.compiler.LocalField;import org.apache.derby.iapi.reference.ClassName;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.sql.compile.CompilerContext;import org.apache.derby.iapi.sql.compile.ExpressionClassBuilderInterface;import org.apache.derby.iapi.sql.execute.ResultSetFactory;import org.apache.derby.iapi.sql.execute.ExecutionFactory;import org.apache.derby.iapi.sql.execute.ExecIndexRow;import org.apache.derby.iapi.sql.Activation;import org.apache.derby.iapi.sql.ParameterValueSet;import org.apache.derby.iapi.sql.Row;import org.apache.derby.iapi.sql.execute.ExecRow;import org.apache.derby.impl.sql.compile.OrderedColumnList;import org.apache.derby.impl.sql.compile.ResultColumnList;import org.apache.derby.impl.sql.execute.IndexColumnOrder;import org.apache.derby.iapi.store.access.ColumnOrdering;import org.apache.derby.iapi.types.DataValueDescriptor;import org.apache.derby.iapi.types.DataTypeDescriptor;import org.apache.derby.iapi.types.DataValueFactory;import org.apache.derby.iapi.types.TypeId;import org.apache.derby.iapi.sql.compile.TypeCompiler;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.util.ByteArray;import org.apache.derby.iapi.services.loader.ClassFactory;import org.apache.derby.iapi.services.loader.GeneratedClass;import org.apache.derby.iapi.services.loader.GeneratedByteCode;import org.apache.derby.iapi.services.loader.GeneratedMethod;import java.lang.reflect.Modifier;import org.apache.derby.iapi.services.classfile.VMOpcode;import org.apache.derby.iapi.services.monitor.Monitor;import org.apache.derby.iapi.services.io.FormatableArrayHolder;import java.io.Serializable;/** * ExpressionClassBuilder * provides an interface to satisfy generation's * common tasks in building classes that involve expressions. * This is the common superclass of ActivationClassBuilder and * FilterClassBuilder. See the documentation on ActivationClassBuilder. * * @author Rick Extracted out of ActivationClassBuilder */public abstract class ExpressionClassBuilder implements ExpressionClassBuilderInterface{ /////////////////////////////////////////////////////////////////////// // // CONSTANTS // /////////////////////////////////////////////////////////////////////// static final protected String currentDatetimeFieldName = "cdt"; /////////////////////////////////////////////////////////////////////// // // STATE // /////////////////////////////////////////////////////////////////////// protected ClassBuilder cb; protected GeneratedClass gc; protected int nextExprNum; protected int nextNonFastExpr; protected int nextFieldNum; protected MethodBuilder constructor; public CompilerContext myCompCtx; public MethodBuilder executeMethod; // to find it fast protected LocalField cdtField; //protected final JavaFactory javaFac; protected MethodBuilder resultSetClosedMethod; private String currentRowScanResultSetName; /////////////////////////////////////////////////////////////////////// // // CONSTRUCTORS // /////////////////////////////////////////////////////////////////////// /** * By the time this is done, it has constructed the following class: * <pre> * public class #className extends #superClass { * public #className() { super(); } * } * </pre> * * @exception StandardException thrown on failure */ public ExpressionClassBuilder (String superClass, String className, CompilerContext cc ) throws StandardException { int modifiers = Modifier.PUBLIC | Modifier.FINAL; myCompCtx = cc; JavaFactory javaFac = myCompCtx.getJavaFactory(); if ( className == null ) { className = myCompCtx.getUniqueClassName(); } // start the class cb = javaFac.newClassBuilder(myCompCtx.getClassFactory(), getPackageName(), modifiers, className, superClass); beginConstructor(); } /////////////////////////////////////////////////////////////////////// // // ABSTRACT METHODS TO BE IMPLEMENTED BY CHILDREN // /////////////////////////////////////////////////////////////////////// /** * Get the name of the package that the generated class will live in. * * @return name of package that the generated class will live in. */ public abstract String getPackageName(); /** * Get the number of ExecRows that must be allocated * * @return number of ExecRows that must be allocated * * @exception StandardException thrown on failure */ public abstract int getRowCount() throws StandardException; /** * Sets the number of subqueries under this expression * * * @exception StandardException thrown on failure */ public abstract void setNumSubqueries() throws StandardException; /** * Generates an expression to refer to a named parameter. * * @param name Parameter name * @param position Parameter number * @param dataType Parameter datatype * @param mb The method to put the generated code into * * @return an expression encoding a reference to the named parameter * * @exception StandardException thrown on failure */ public abstract void getParameterReference( String name, int position, DataTypeDescriptor dataType, MethodBuilder mb ) throws StandardException; /** * Build boiler plate for the Execute method * * * @return a method builder containing boiler plate for the Execute method * * @exception StandardException thrown on failure */ public abstract MethodBuilder beginExecuteMethod() throws StandardException; /** * Finish up the Execute method. * * * @exception StandardException thrown on failure */ public abstract void finishExecuteMethod(boolean genMarkAsTopNode ) throws StandardException; /////////////////////////////////////////////////////////////////////// // // ACCESSORS // /////////////////////////////////////////////////////////////////////// /** Return the base class of the activation's hierarchy (the subclass of Object). This class is expected to hold methods used by all compilation code, such as datatype compilation code, e.g. getDataValueFactory. */ abstract public String getBaseClassName(); public MethodBuilder getConstructor() { return constructor; } public ClassBuilder getClassBuilder() { return cb; } /** * The execute method returns a result set that will evaluate the * statement this activation class is the compiled form of. * REVISIT: do we need to give the caller the ability to touch it * directly, or could we wrap the alterations to it in this class? */ public MethodBuilder getExecuteMethod() { return executeMethod; } /////////////////////////////////////////////////////////////////////// // // CONSTRUCTOR MANAGEMENT // /////////////////////////////////////////////////////////////////////// private final void beginConstructor() { // create a constructor that just calls super. MethodBuilder realConstructor = cb.newConstructorBuilder(Modifier.PUBLIC); realConstructor.callSuper(); realConstructor.methodReturn(); realConstructor.complete(); constructor = cb.newMethodBuilder(Modifier.PUBLIC, "void", "postConstructor"); constructor.addThrownException(ClassName.StandardException); } /** * Finish the constructor by newing the array of Rows and putting a return * at the end of it. * * @exception StandardException thrown on failure * @return Nothing */ public void finishConstructor() throws StandardException { int numResultSets; /* Set the number of subqueries */ setNumSubqueries(); numResultSets = getRowCount(); /* Generate the new of ExecRow[numResultSets] when there are ResultSets * which return Rows. */ if (numResultSets >= 1) { addNewArrayOfRows(numResultSets); } /* Generated code is: * return; */ constructor.methodReturn(); constructor.complete(); } /** * Generate the assignment for row = new ExecRow[numResultSets] * * @param numResultSets The size of the array. * * @return Nothing. */ private void addNewArrayOfRows(int numResultSets) { /* Generated code is: * row = new ExecRow[numResultSets]; */ constructor.pushThis(); constructor.pushNewArray(ClassName.ExecRow, numResultSets); constructor.putField(ClassName.BaseActivation, "row", ClassName.ExecRow + "[]"); constructor.endStatement(); } /////////////////////////////////////////////////////////////////////// // // ADD FIELDS TO GENERATED CLASS // /////////////////////////////////////////////////////////////////////// /** * Add a field declaration to the generated class * * @param modifiers The | of the modifier values such as public, static, etc. * @param type The type of the field in java language. * @param name The name of the field. * * @return None. */ public LocalField newFieldDeclaration(int modifiers, String type, String name) { return cb.addField(type, name, modifiers); } /** * Add an arbitrarily named field to the generated class. * * This is used to generate fields where the caller doesn't care what * the field is named. It is especially useful for generating arbitrary * numbers of fields, where the caller doesn't know in advance how many * fields will be used. For example, it is used for generating fields * to hold intermediate values from expressions. * * @param modifiers The | of the modifier values such as public, static, etc. * @param type The type of the field in java language. * * @return The name of the new field */ public LocalField newFieldDeclaration(int modifiers, String type) { return cb.addField(type, newFieldName(), modifiers); } /////////////////////////////////////////////////////////////////////// // // ADD FUNCTIONS TO GENERATED CLASS // /////////////////////////////////////////////////////////////////////// /** * Activations might have need of internal functions * that are not used by the result sets, but by other * activation functions. Thus, we make it possible * for functions to be generated directly as well * as through the newExprFun interface. newExprFun * should be used when a static field pointing to the * expression function is needed. * <p> * The generated function will generally have a generated name * that can be viewed through the MethodBuilder interface. * This name is generated to ensure uniqueness from other * function names in the activation class. If you pass in a function * name, think carefully about whether it will collide with other names. * * @param exprName Name of function. Usually null, which causes us to * generate a unique name. * @param returnType the return type of the function * @param modifiers the modifiers on the function * * @see #newExprFun */ public MethodBuilder newGeneratedFun(String returnType, int modifiers) { return newGeneratedFun(returnType, modifiers, (String[]) null); } public MethodBuilder newGeneratedFun(String returnType, int modifiers, String[] params) { String exprName = "g".concat(Integer.toString(nextNonFastExpr++)); return newGeneratedFun(exprName, returnType, modifiers, params); } private MethodBuilder newGeneratedFun(String exprName, String returnType, int modifiers, String[] params) { // // create a new method supplying the given modifiers and return Type // Java: #modifiers #returnType #exprName { } // MethodBuilder exprMethod; if (params == null) { exprMethod = cb.newMethodBuilder(modifiers, returnType, exprName); } else { exprMethod = cb.newMethodBuilder(modifiers, returnType, exprName, params); } // // declare it to throw StandardException // Java: #modifiers #returnType #exprName throws StandardException { } // exprMethod.addThrownException(ClassName.StandardException); return exprMethod; } /** * "ExprFun"s are the "expression functions" that * are specific to a given JSQL statement. For example, * an ExprFun is generated to evaluate the where clause * of a select statement and return a boolean result. * <p> * * All methods return by this are expected to be called * via the GeneratedMethod interface. Thus the methods * are public and return java.lang.Object. * <p> * Once the exprfun has been created, the * caller will need to add statements to it, * minimally a return statement. * <p> * ExprFuns return Object types, since they * are invoked through reflection and thus their * return type would get wrapped in an object anyway. * For example: return java.lang.Boolean, not boolean. */ public MethodBuilder newExprFun() { // get next generated function String exprName = "e".concat(Integer.toString(nextExprNum++)); return newGeneratedFun(exprName, "java.lang.Object", Modifier.PUBLIC, (String[]) null); } /** Push an expression that is a GeneratedMethod reference to the passed in method. aka. a "function pointer". */ public void pushMethodReference(MethodBuilder mb, MethodBuilder exprMethod) { mb.pushThis(); // instance mb.push(exprMethod.getName()); // arg mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.GeneratedByteCode, "getMethod", ClassName.GeneratedMethod, 1 ); } /** * Start a user expression. The difference between a normal expression * (returned by newExprFun) * and a user expression is that a user expression catches all exceptions * (because we don't want random exceptions thrown from user methods to * propagate to the rest of the system. * * @param functionName Name to give to the function. If null, we'll generate a * unique name. * @param returnType A String telling the return type from the expression * * @return A new MethodBuilder */ public MethodBuilder newUserExprFun() { MethodBuilder mb = newExprFun(); mb.addThrownException("java.lang.Exception"); return mb;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -