📄 methodcallnode.java
字号:
outerSubqueryList, outerPredicateList); } } } } /** * Categorize this predicate. Initially, this means * building a bit map of the referenced tables for each predicate. * If the source of this ColumnReference (at the next underlying level) * is not a ColumnReference or a VirtualColumnNode then this predicate * will not be pushed down. * * For example, in: * select * from (select 1 from s) a (x) where x = 1 * we will not push down x = 1. * NOTE: It would be easy to handle the case of a constant, but if the * inner SELECT returns an arbitrary expression, then we would have to copy * that tree into the pushed predicate, and that tree could contain * subqueries and method calls. * RESOLVE - revisit this issue once we have views. * * @param referencedTabs JBitSet with bit map of referenced FromTables * @param simplePredsOnly Whether or not to consider method * calls, field references and conditional nodes * when building bit map * * @return boolean Whether or not source.expression is a ColumnReference * or a VirtualColumnNode. * @exception StandardException Thrown on error */ public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly) throws StandardException { /* We stop here when only considering simple predicates * as we don't consider method calls when looking * for null invariant predicates. */ if (simplePredsOnly) { return false; } boolean pushable = true; int param; if (methodParms != null) { for (param = 0; param < methodParms.length; param++) { if (methodParms[param] != null) { pushable = methodParms[param].categorize(referencedTabs, simplePredsOnly) && pushable; } } } /* We need to push down method call. Then the predicate can be used for start/stop * key for index scan. The fact that method call's cost is not predictable and can * be expensive doesn't mean we shouldn't push it down. Beetle 4826. */ return pushable; } /** * Remap all ColumnReferences in this tree to be clones of the * underlying expression. * * @return JavaValueNode The remapped expression tree. * * @exception StandardException Thrown on error */ public JavaValueNode remapColumnReferencesToExpressions() throws StandardException { int param; if (methodParms != null) { for (param = 0; param < methodParms.length; param++) { if (methodParms[param] != null) { methodParms[param] = methodParms[param].remapColumnReferencesToExpressions(); } } } return this; } /** * Generate the parameters to the given method call * * @param acb The ExpressionClassBuilder for the class we're generating * @param mb the method the expression will go into * * @return Count of arguments to the method. * * @exception StandardException Thrown on error */ public int generateParameters(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException { int param; String[] expectedTypes = methodParameterTypes; ClassInspector classInspector = getClassFactory().getClassInspector(); /* Generate the code for each user parameter, generating the appropriate * cast when the passed type needs to get widened to the expected type. */ for (param = 0; param < methodParms.length; param++) { generateOneParameter( acb, mb, param ); // type from the SQL-J expression String argumentType = getParameterTypeName( methodParms[param] ); // type of the method String parameterType = expectedTypes[param]; if (!parameterType.equals(argumentType)) { // since we reached here through method resolution // casts are only required for primitive types. // In any other case the expression type must be assignable // to the parameter type. if (classInspector.primitiveType(parameterType)) { mb.cast(parameterType); } else { // for a prodcedure if (routineInfo != null) { continue; // probably should be only for INOUT/OUT parameters. } if (SanityManager.DEBUG) { SanityManager.ASSERT(classInspector.assignableTo(argumentType, parameterType), "Argument type " + argumentType + " is not assignable to parameter " + parameterType); } /* ** Set the parameter type in case the argument type is narrower ** than the parameter type. */ mb.upCast(parameterType); } } } return methodParms.length; } static public String getParameterTypeName( JavaValueNode param ) throws StandardException { String argumentType; // RESOLVE - shouldn't this logic be inside JavaValueNode ?? // I.e. once the value is primitive then its java type name is its // primitive type name. if (param.isPrimitiveType()) { argumentType = param.getPrimitiveTypeName(); } else { argumentType = param.getJavaTypeName(); } return argumentType; } /** * Generate one parameter to the given method call. This method is overriden by * RepStaticMethodCallNode. * * @param acb The ExpressionClassBuilder for the class we're generating * @param mb the method the expression will go into * @param parameterNumber Identifies which parameter to generate. 0 based. * * @return Nothing * * @exception StandardException Thrown on error */ public void generateOneParameter(ExpressionClassBuilder acb, MethodBuilder mb, int parameterNumber ) throws StandardException { methodParms[parameterNumber].generateExpression(acb, mb); } /** * Set the appropriate type information for a null passed as a parameter. * This method is called after method resolution, when a signature was * successfully matched. * * @param parmTypeNames String[] with the java type names for the parameters * as declared by the method * * @return Nothing. * * @exception StandardException Thrown on error */ public void setNullParameterInfo(String[] parmTypeNames) throws StandardException { for (int i = 0; i < methodParms.length; i++) { /* null parameters are represented by a java type name of "" */ if (methodParms[i].getJavaTypeName().equals("")) { /* Set the type information in the null constant node */ DataTypeDescriptor dts = DataTypeDescriptor.getSQLDataTypeDescriptor(parmTypeNames[i]); ((SQLToJavaValueNode)methodParms[i]).value.setDescriptor( dts); /* Set the correct java type name */ methodParms[i].setJavaTypeName(parmTypeNames[i]); signature[i] = methodParms[i].getJSQLType(); } } } protected void resolveMethodCall(String javaClassName, boolean staticMethod) throws StandardException { // only allow direct method calls through routines and internal SQL. if (routineInfo == null && !internalCall) { // See if we are being executed in an internal context if ((getCompilerContext().getReliability() & CompilerContext.INTERNAL_SQL_ILLEGAL) != 0) { throw StandardException.newException(SQLState.LANG_SYNTAX_ERROR, javaClassName + (staticMethod ? "::" : ".") + methodName); } } int count = signature.length; ClassInspector classInspector = getClassFactory().getClassInspector(); String[] parmTypeNames; String[] primParmTypeNames = null; boolean[] isParam = getIsParam(); boolean hasDynamicResultSets = (routineInfo != null) && (count != 0) && (count != methodParms.length); /* ** Find the matching method that is public. */ int signatureOffset = methodName.indexOf('('); // support Java signatures by checking if the method name contains a '(' if (signatureOffset != -1) { parmTypeNames = parseValidateSignature(methodName, signatureOffset, hasDynamicResultSets); methodName = methodName.substring(0, signatureOffset); // If the signature is specified then Derby resolves to exactly // that method. Setting this flag to false disables the method // resolution from automatically optionally repeating the last // parameter as needed. hasDynamicResultSets = false; } else { parmTypeNames = getObjectSignature(); } try { method = classInspector.findPublicMethod(javaClassName, methodName, parmTypeNames, null, isParam, staticMethod, hasDynamicResultSets); // DB2 LUW does not support Java object types for SMALLINT, INTEGER, BIGINT, REAL, DOUBLE // and these are the only types that can map to a primitive or an object type according // to SQL part 13. So we never have a second chance match. // Also if the DDL specified a signature, then no alternate resolution if (signatureOffset == -1 && routineInfo == null) { /* If no match, then retry with combinations of object and * primitive types. */ if (method == null) { primParmTypeNames = getPrimitiveSignature(false); method = classInspector.findPublicMethod(javaClassName, methodName, parmTypeNames, primParmTypeNames, isParam, staticMethod, hasDynamicResultSets); } } } catch (ClassNotFoundException e) { /* ** If one of the classes couldn't be found, just act like the ** method couldn't be found. The error lists all the class names, ** which should give the user enough info to diagnose the problem. */ method = null; } /* Throw exception if no matching signature found */ if (method == null) { throwNoMethodFound(javaClassName, parmTypeNames, primParmTypeNames); } String typeName = classInspector.getType(method); actualMethodReturnType = typeName; if (routineInfo == null) { /* void methods are only okay for CALL Statements */ if (typeName.equals("void")) { if (!forCallStatement) throw StandardException.newException(SQLState.LANG_VOID_METHOD_CALL); } } else { String promoteName = null; TypeDescriptor returnType = routineInfo.getReturnType(); String requiredType; if (returnType == null) { // must have a void method for a procedure call. requiredType = "void"; } else { // DB2 LUW does not support Java object types for SMALLINT, INTEGER, BIGINT, REAL, DOUBLE // and these are the only types that can map to a primitive or an object type according // to SQL part 13. So always map to the primitive type. We can not use the getPrimitiveSignature() // as it (incorrectly but historically always has) maps a DECIMAL to a double. TypeId returnTypeId = TypeId.getBuiltInTypeId(returnType.getJDBCTypeId()); switch (returnType.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: TypeCompiler tc = getTypeCompiler(returnTypeId); requiredType = tc.getCorrespondingPrimitiveTypeName(); if (!routineInfo.calledOnNullInput() && routineInfo.getParameterCount() != 0) { promoteName = returnTypeId.getCorrespondingJavaTypeName(); } break; default: requiredType = returnTypeId.getCorrespondingJavaTypeName(); break; } } if (!requiredType.equals(typeName)) { throwNoMethodFound(requiredType + " " + javaClassName, parmTypeNames, primParmTypeNames); } // for a returns null on null input with a primitive // type we need to promote to an object so we can return null. if (promoteName != null) typeName = promoteName; } setJavaTypeName( typeName ); methodParameterTypes = classInspector.getParameterTypes(method); for (int i = 0; i < methodParameterTypes.length; i++) { String methodParameter = methodParameterTypes[i]; if (routineInfo != null) { if (i < routineInfo.getParameterCount()) { int parameterMode = routineInfo.getParameterModes()[i]; switch (parameterMode) { case JDBC30Translation.PARAMETER_MODE_IN: break; case JDBC30Translation.PARAMETER_MODE_IN_OUT: // we need to see if the type of the array is // primitive, not the array itself. methodParameter = methodParameter.substring(0, methodParameter.length() - 2); break; case JDBC30Translation.PARAMETER_MODE_OUT: // value is not obtained *from* parameter. continue; } } } if (ClassInspector.primitiveType(methodParameter)) methodParms[i].castToPrimitive(true); } /* Set type info for any null parameters */ if ( someParametersAreNull() ) { setNullParameterInfo(methodParameterTypes); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -