📄 staticmethodcallnode.java
字号:
// if it's not an exact length match then some cast will be needed. if (!paramdtd.isExactTypeAndLengthMatch(dts)) needCast = true; } } else { // any variable length type will need a cast from the // Java world (the ? parameter) to the SQL type. This // ensures values like CHAR(10) are passed into the procedure // correctly as 10 characters long. if (parameterTypeId.variableLength()) { if (parameterMode != JDBC30Translation.PARAMETER_MODE_OUT) needCast = true; } } if (needCast) { // push a cast node to ensure the // correct type is passed to the method // this gets tacky because before we knew // it was a procedure call we ensured all the // parameter are JavaNodeTypes. Now we need to // push them back to the SQL domain, cast them // and then push them back to the Java domain. if (sqlParamNode == null) { sqlParamNode = (ValueNode) getNodeFactory().getNode( C_NodeTypes.JAVA_TO_SQL_VALUE_NODE, methodParms[p], getContextManager()); } ValueNode castNode = (ValueNode) getNodeFactory().getNode( C_NodeTypes.CAST_NODE, sqlParamNode, paramdtd, getContextManager()); methodParms[p] = (JavaValueNode) getNodeFactory().getNode( C_NodeTypes.SQL_TO_JAVA_VALUE_NODE, castNode, getContextManager()); methodParms[p] = methodParms[p].bindExpression(fromList, subqueryList, aggregateVector); } // only force the type for a ? so that the correct type shows up // in parameter meta data if (isParameterMarker) sqlParamNode.setDescriptor(paramdtd); } if (sigParameterCount != parameterCount) { TypeId typeId = TypeId.getUserDefinedTypeId("java.sql.ResultSet[]", false); DataTypeDescriptor dtd = new DataTypeDescriptor( typeId, 0, 0, false, -1 ); signature[parameterCount] = new JSQLType(dtd); } this.routineInfo = routineInfo; ad = proc; // If a procedure is in the system schema and defined as executing // SQL do we set we are in system code. if (sd.isSystemSchema() && (routineInfo.getReturnType() == null) && routineInfo.getSQLAllowed() != RoutineAliasInfo.NO_SQL) isSystemCode = true; break; } } } /* Throw exception if no alias found */ if (ad == null) { Object errName; if (procedureName == null) errName = methodName; else errName = procedureName; throw StandardException.newException(SQLState.LANG_NO_SUCH_METHOD_ALIAS, errName); } /* Query is dependent on the AliasDescriptor */ cc.createDependency(ad); methodName = ad.getAliasInfo().getMethodName(); javaClassName = ad.getJavaClassName(); } javaClassName = verifyClassExist(javaClassName, true); /* Resolve the method call */ resolveMethodCall(javaClassName, true); alreadyBound = true; // If this is a function call with a variable length // return type, then we need to push a CAST node. if (routineInfo != null) { TypeDescriptor returnType = routineInfo.getReturnType(); if (returnType != null) { TypeId returnTypeId = TypeId.getBuiltInTypeId(returnType.getJDBCTypeId()); if (returnTypeId.variableLength()) { // Cast the return using a cast node, but have to go // into the SQL domain, and back to the Java domain. DataTypeDescriptor returnValueDtd = new DataTypeDescriptor( returnTypeId, returnType.getPrecision(), returnType.getScale(), returnType.isNullable(), returnType.getMaximumWidth() ); ValueNode returnValueToSQL = (ValueNode) getNodeFactory().getNode( C_NodeTypes.JAVA_TO_SQL_VALUE_NODE, this, getContextManager()); ValueNode returnValueCastNode = (ValueNode) getNodeFactory().getNode( C_NodeTypes.CAST_NODE, returnValueToSQL, returnValueDtd, getContextManager()); JavaValueNode returnValueToJava = (JavaValueNode) getNodeFactory().getNode( C_NodeTypes.SQL_TO_JAVA_VALUE_NODE, returnValueCastNode, getContextManager()); return returnValueToJava.bindExpression(fromList, subqueryList, aggregateVector); } } } return this; } /** Push extra code to generate the casts within the arrays for the parameters passed as arrays. */ public void generateOneParameter(ExpressionClassBuilder acb, MethodBuilder mb, int parameterNumber ) throws StandardException { int parameterMode; SQLToJavaValueNode sql2j = null; if (methodParms[parameterNumber] instanceof SQLToJavaValueNode) sql2j = (SQLToJavaValueNode) methodParms[parameterNumber]; if (routineInfo != null) { parameterMode = routineInfo.getParameterModes()[parameterNumber]; } else { // for a static method call the parameter always starts out as a in parameter, but // may be registered as an IN OUT parameter. For a static method argument to be // a dynmaically registered out parameter it must be a simple ? parameter parameterMode = JDBC30Translation.PARAMETER_MODE_IN; if (sql2j != null) { if (sql2j.getSQLValueNode().isParameterNode()) { // applicationParameterNumbers is only set up for a procedure. int applicationParameterNumber = ((ParameterNode) (sql2j.getSQLValueNode())).getParameterNumber(); String parameterType = methodParameterTypes[parameterNumber]; if (parameterType.endsWith("[]")) { // constructor - setting up correct paramter type info MethodBuilder constructor = acb.getConstructor(); acb.pushThisAsActivation(constructor); constructor.callMethod(VMOpcode.INVOKEINTERFACE, null, "getParameterValueSet", ClassName.ParameterValueSet, 0); constructor.push(applicationParameterNumber); constructor.push(JDBC30Translation.PARAMETER_MODE_UNKNOWN); constructor.callMethod(VMOpcode.INVOKEINTERFACE, null, "setParameterMode", "void", 2); constructor.endStatement(); } } } } switch (parameterMode) { case JDBC30Translation.PARAMETER_MODE_IN: case JDBC30Translation.PARAMETER_MODE_IN_OUT: case JDBC30Translation.PARAMETER_MODE_UNKNOWN: if (sql2j != null) sql2j.returnsNullOnNullState = returnsNullOnNullState; super.generateOneParameter(acb, mb, parameterNumber); break; case JDBC30Translation.PARAMETER_MODE_OUT: // For an OUT parameter we require nothing to be pushed into the // method call from the parameter node. break; } switch (parameterMode) { case JDBC30Translation.PARAMETER_MODE_IN: case JDBC30Translation.PARAMETER_MODE_UNKNOWN: break; case JDBC30Translation.PARAMETER_MODE_IN_OUT: case JDBC30Translation.PARAMETER_MODE_OUT: { // Create the array used to pass into the method. We create a // new array for each call as there is a small chance the // application could retain a reference to it and corrupt // future calls with the same CallableStatement object. String methodParameterType = methodParameterTypes[parameterNumber]; String arrayType = methodParameterType.substring(0, methodParameterType.length() - 2); LocalField lf = acb.newFieldDeclaration(Modifier.PRIVATE, methodParameterType); if (outParamArrays == null) outParamArrays = new LocalField[methodParms.length]; outParamArrays[parameterNumber] = lf; mb.pushNewArray(arrayType, 1); mb.putField(lf); // set the IN part of the parameter into the INOUT parameter. if (parameterMode != JDBC30Translation.PARAMETER_MODE_OUT) { mb.swap(); mb.setArrayElement(0); mb.getField(lf); } break; } } } /** * 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; pushable = pushable && super.categorize(referencedTabs, simplePredsOnly); return pushable; } /** * Convert this object to a String. See comments in QueryTreeNode.java * for how this should be done for tree printing. * * @return This object as a String */ public String toString() { if (SanityManager.DEBUG) { return "javaClassName: " + (javaClassName != null ? javaClassName : "null") + "\n" + super.toString(); } else { return ""; } } /** * Do code generation for this method call * * @param acb The ExpressionClassBuilder for the class we're generating
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -