📄 staticmethodcallnode.java
字号:
/* Derby - Class org.apache.derby.impl.sql.compile.StaticMethodCallNode 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.MethodBuilder;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.sql.compile.CompilerContext;import org.apache.derby.iapi.sql.compile.TypeCompiler;import org.apache.derby.iapi.sql.compile.C_NodeTypes;import org.apache.derby.iapi.types.JSQLType;import org.apache.derby.iapi.types.DataTypeDescriptor;import org.apache.derby.iapi.types.TypeId;import org.apache.derby.iapi.sql.dictionary.AliasDescriptor;import org.apache.derby.iapi.sql.dictionary.DataDictionary;import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;import org.apache.derby.iapi.reference.ClassName;import org.apache.derby.iapi.reference.SQLState;import org.apache.derby.iapi.reference.JDBC30Translation;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;import org.apache.derby.iapi.services.loader.ClassInspector;import org.apache.derby.iapi.services.compiler.LocalField;import org.apache.derby.iapi.util.JBitSet;import org.apache.derby.iapi.services.classfile.VMOpcode;import org.apache.derby.iapi.sql.conn.Authorizer;import org.apache.derby.catalog.AliasInfo;import org.apache.derby.catalog.TypeDescriptor;import org.apache.derby.catalog.types.RoutineAliasInfo;import org.apache.derby.impl.sql.compile.ActivationClassBuilder;import org.apache.derby.catalog.UUID;import java.util.Vector;import java.lang.reflect.Modifier;/** * A StaticMethodCallNode represents a static method call from a Class * (as opposed to from an Object). For a procedure the call requires that the arguments be ? parameters. The parameter is *logically* passed into the method call a number of different ways. <P> For a application call like CALL MYPROC(?) the logically Java method call is (in psuedo Java/SQL code) (examples with CHAR(10) parameter) <BR> Fixed length IN parameters - com.acme.MyProcedureMethod(?) <BR> Variable length IN parameters - com.acme.MyProcedureMethod(CAST (? AS CHAR(10)) <BR> Fixed length INOUT parameter - String[] holder = new String[] {?}; com.acme.MyProcedureMethod(holder); ? = holder[0] <BR> Variable length INOUT parameter - String[] holder = new String[] {CAST (? AS CHAR(10)}; com.acme.MyProcedureMethod(holder); ? = CAST (holder[0] AS CHAR(10)) <BR> Fixed length OUT parameter - String[] holder = new String[1]; com.acme.MyProcedureMethod(holder); ? = holder[0] <BR> Variable length INOUT parameter - String[] holder = new String[1]; com.acme.MyProcedureMethod(holder); ? = CAST (holder[0] AS CHAR(10)) <P> For static method calls there is no pre-definition of an IN or INOUT parameter, so a call to CallableStatement.registerOutParameter() makes the parameter an INOUT parameter, provided: - the parameter is passed directly to the method call (no casts or expressions). - the method's parameter type is a Java array type. Since this is a dynmaic decision we compile in code to take both paths, based upon a boolean isINOUT which is dervied from the ParameterValueSet. Code is logically (only single parameter String[] shown here). Note, no casts can exist here. boolean isINOUT = getParameterValueSet().getParameterMode(0) == PARAMETER_IN_OUT; if (isINOUT) { String[] holder = new String[] {?}; com.acme.MyProcedureMethod(holder); ? = holder[0] } else { com.acme.MyProcedureMethod(?) } * * @author Jerry Brenner */public class StaticMethodCallNode extends MethodCallNode{ private TableName procedureName; private LocalField[] outParamArrays; private int[] applicationParameterNumbers; private boolean isSystemCode; private boolean alreadyBound; private LocalField returnsNullOnNullState; AliasDescriptor ad; /** * Intializer for a NonStaticMethodCallNode * * @param methodName The name of the method to call * @param javaClassName The name of the java class that the static method belongs to. */ public void init(Object methodName, Object javaClassName) { if (methodName instanceof String) init(methodName); else { procedureName = (TableName) methodName; init(procedureName.getTableName()); } this.javaClassName = (String) javaClassName; } /** * Bind this expression. This means binding the sub-expressions, * as well as figuring out what the return type is for this expression. * * @param fromList The FROM list for the query this * expression is in, for binding columns. * @param subqueryList The subquery list being built as we find SubqueryNodes * @param aggregateVector The aggregate vector being built as we find AggregateNodes * * @return this or an AggregateNode * * @exception StandardException Thrown on error */ public JavaValueNode bindExpression( FromList fromList, SubqueryList subqueryList, Vector aggregateVector) throws StandardException { // for a function we can get called recursively if (alreadyBound) return this; bindParameters(fromList, subqueryList, aggregateVector); /* If javaClassName is null then we assume that the current methodName * is an alias and we must go to sysmethods to * get the real method and java class names for this alias. */ if (javaClassName == null) { CompilerContext cc = getCompilerContext(); // look for a routine if (ad == null) { String schemaName = procedureName != null ? procedureName.getSchemaName() : null; SchemaDescriptor sd = getSchemaDescriptor(schemaName, schemaName != null); if (sd.getUUID() != null) { java.util.List list = getDataDictionary().getRoutineList( sd.getUUID().toString(), methodName, forCallStatement ? AliasInfo.ALIAS_NAME_SPACE_PROCEDURE_AS_CHAR : AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR ); for (int i = list.size() - 1; i >= 0; i--) { AliasDescriptor proc = (AliasDescriptor) list.get(i); RoutineAliasInfo routineInfo = (RoutineAliasInfo) proc.getAliasInfo(); int parameterCount = routineInfo.getParameterCount(); if (parameterCount != methodParms.length) continue; // pre-form the method signature. If it is a dynamic result set procedure // then we need to add in the ResultSet array TypeDescriptor[] parameterTypes = routineInfo.getParameterTypes(); int sigParameterCount = parameterCount; if (routineInfo.getMaxDynamicResultSets() > 0) sigParameterCount++; signature = new JSQLType[sigParameterCount]; for (int p = 0; p < parameterCount; p++) { // find the declared type. TypeDescriptor td = parameterTypes[p]; TypeId typeId = TypeId.getBuiltInTypeId(td.getJDBCTypeId()); TypeId parameterTypeId = typeId; // if it's an OUT or INOUT parameter we need an array. int parameterMode = routineInfo.getParameterModes()[p]; if (parameterMode != JDBC30Translation.PARAMETER_MODE_IN) { String arrayType; switch (typeId.getJDBCTypeId()) { case java.sql.Types.SMALLINT: case java.sql.Types.INTEGER: case java.sql.Types.BIGINT: case java.sql.Types.REAL: case java.sql.Types.DOUBLE: arrayType = getTypeCompiler(typeId).getCorrespondingPrimitiveTypeName().concat("[]"); break; default: arrayType = typeId.getCorrespondingJavaTypeName().concat("[]"); break; } typeId = TypeId.getUserDefinedTypeId(arrayType, false); } // this is the type descriptor of the require method parameter DataTypeDescriptor methoddtd = new DataTypeDescriptor( typeId, td.getPrecision(), td.getScale(), td.isNullable(), td.getMaximumWidth() ); signature[p] = new JSQLType(methoddtd); // check parameter is a ? node for INOUT and OUT parameters. ValueNode sqlParamNode = null; if (methodParms[p] instanceof SQLToJavaValueNode) { SQLToJavaValueNode sql2j = (SQLToJavaValueNode) methodParms[p]; sqlParamNode = sql2j.getSQLValueNode(); } else { } boolean isParameterMarker = true; if ((sqlParamNode == null) || !sqlParamNode.isParameterNode()) { if (parameterMode != JDBC30Translation.PARAMETER_MODE_IN) { throw StandardException.newException(SQLState.LANG_DB2_PARAMETER_NEEDS_MARKER, RoutineAliasInfo.parameterMode(parameterMode), routineInfo.getParameterNames()[p]); } isParameterMarker = false; } else { if (applicationParameterNumbers == null) applicationParameterNumbers = new int[parameterCount]; applicationParameterNumbers[p] = ((ParameterNode) sqlParamNode).getParameterNumber(); } // this is the SQL type of the procedure parameter. DataTypeDescriptor paramdtd = new DataTypeDescriptor( parameterTypeId, td.getPrecision(), td.getScale(), td.isNullable(), td.getMaximumWidth() ); boolean needCast = false; if (!isParameterMarker) { // can only be an IN parameter. // check that the value can be assigned to the // type of the procedure parameter. if (sqlParamNode instanceof UntypedNullConstantNode) { sqlParamNode.setDescriptor(paramdtd); } else { DataTypeDescriptor dts; TypeId argumentTypeId; if (sqlParamNode != null) { // a node from the SQL world argumentTypeId = sqlParamNode.getTypeId(); dts = sqlParamNode.getTypeServices(); } else { // a node from the Java world dts = DataTypeDescriptor.getSQLDataTypeDescriptor(methodParms[p].getJavaTypeName()); if (dts == null) { throw StandardException.newException(SQLState.LANG_NO_CORRESPONDING_S_Q_L_TYPE, methodParms[p].getJavaTypeName()); } argumentTypeId = dts.getTypeId(); } if (! getTypeCompiler(parameterTypeId).storable(argumentTypeId, getClassFactory())) throw StandardException.newException(SQLState.LANG_NOT_STORABLE, parameterTypeId.getSQLTypeName(), argumentTypeId.getSQLTypeName() );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -