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.requiresTypeFromContext())
{
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];
if (sqlParamNode instanceof UnaryOperatorNode) {
ParameterNode pn = ((UnaryOperatorNode)sqlParamNode).getParameterOperand();
applicationParameterNumbers[p] = pn.getParameterNumber();
} else
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.setType(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() );
// 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.setType(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;