mb.pushThis();
}
int nargs = generateParameters(acb, mb);
LocalField functionEntrySQLAllowed = null;
if (routineInfo != null) {
short sqlAllowed = routineInfo.getSQLAllowed();
// Before we set up our authorization level, add a check to see if this
// method can be called. If the routine is NO SQL or CONTAINS SQL
// then there is no need for a check. As follows:
//
// Current Level = NO_SQL - CALL will be rejected when getting CALL result set
// Current Level = anything else - calls to procedures defined as NO_SQL and CONTAINS SQL both allowed.
if (sqlAllowed != RoutineAliasInfo.NO_SQL)
{
int sqlOperation;
if (sqlAllowed == RoutineAliasInfo.READS_SQL_DATA)
sqlOperation = Authorizer.SQL_SELECT_OP;
else if (sqlAllowed == RoutineAliasInfo.MODIFIES_SQL_DATA)
sqlOperation = Authorizer.SQL_WRITE_OP;
else
sqlOperation = Authorizer.SQL_ARBITARY_OP;
generateAuthorizeCheck((ActivationClassBuilder) acb, mb, sqlOperation);
}
int statmentContextReferences = isSystemCode ? 2 : 1;
boolean isFunction = routineInfo.getReturnType() != null;
if (isFunction)
statmentContextReferences++;
if (statmentContextReferences != 0) {
acb.pushThisAsActivation(mb);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
"getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
"getStatementContext", "org.apache.derby.iapi.sql.conn.StatementContext", 0);
for (int scc = 1; scc < statmentContextReferences; scc++)
mb.dup();
}
/**
Set the statement context to reflect we are running
System procedures, so that we can execute non-standard SQL.
*/
if (isSystemCode) {
mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
"setSystemCode", "void", 0);
}
// If no SQL, there is no need to setup a nested session
// context.
if (sqlAllowed != RoutineAliasInfo.NO_SQL) {
generateSetupNestedSessionContext(
(ActivationClassBuilder) acb,
mb,
routineInfo.hasDefinersRights(),
routineDefiner);
}
// for a function we need to fetch the current SQL control
// so that we can reset it once the function is complete.
//
if (isFunction)
{
functionEntrySQLAllowed = acb.newFieldDeclaration(Modifier.PRIVATE, "short");
mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
"getSQLAllowed", "short", 0);
mb.setField(functionEntrySQLAllowed);
}
// Set up the statement context to reflect the
// restricted SQL execution allowed by this routine.
mb.push(sqlAllowed);
mb.push(false);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
"setSQLAllowed", "void", 2);
}
// add in the ResultSet arrays. note that varargs and dynamic ResultSets
// both make claims on the trailing arguments of the method invocation.
// a routine may make use of both varargs and dynamic ResultSets.
if ( routineInfo != null && !hasVarargs() )
{
int compiledResultSets = methodParameterTypes.length - methodParms.length;
if (compiledResultSets != 0) {
// Add a method that indicates the maxium number of dynamic result sets.
int maxDynamicResults = routineInfo.getMaxDynamicResultSets();
if (maxDynamicResults > 0) {
MethodBuilder gdr = acb.getClassBuilder().newMethodBuilder(Modifier.PUBLIC, "int", "getMaxDynamicResults");
gdr.push(maxDynamicResults);
gdr.methodReturn();
gdr.complete();
}
// add a method to return all the dynamic result sets (unordered)
MethodBuilder gdr = acb.getClassBuilder().newMethodBuilder(Modifier.PUBLIC, "java.sql.ResultSet[][]", "getDynamicResults");
MethodBuilder cons = acb.getConstructor();
// if (procDef.getParameterStyle() == RoutineAliasInfo.PS_JAVA)
{
// PARAMETER STYLE JAVA
LocalField procedureResultSetsHolder = acb.newFieldDeclaration(Modifier.PRIVATE, "java.sql.ResultSet[][]");
// getDynamicResults body
gdr.getField(procedureResultSetsHolder);
// create the holder of all the ResultSet arrays, new java.sql.ResultSet[][compiledResultSets]
cons.pushNewArray("java.sql.ResultSet[]", compiledResultSets);
cons.setField(procedureResultSetsHolder);
// arguments for the dynamic result sets
for (int i = 0; i < compiledResultSets; i++) {
mb.pushNewArray("java.sql.ResultSet", 1);
mb.dup();
mb.getField(procedureResultSetsHolder);
mb.swap();
mb.setArrayElement(i);
}
}
// complete the method that returns the ResultSet[][] to the
gdr.methodReturn();
gdr.complete();
nargs += compiledResultSets;
}
}
String javaReturnType = getJavaTypeName();
MethodBuilder mbnc = null;
MethodBuilder mbcm = mb;
// If any of the parameters are null then
// do not call the method, just return null.
if (returnsNullOnNullState != null)
{
mbnc = acb.newGeneratedFun(javaReturnType, Modifier.PRIVATE, methodParameterTypes);
// add the throws clause for the public static method we are going to call.
Class[] throwsSet = ((java.lang.reflect.Method) method).getExceptionTypes();
for (int te = 0; te < throwsSet.length; te++)
{
mbnc.addThrownException(throwsSet[te].getName());
}
mbnc.getField(returnsNullOnNullState);
mbnc.conditionalIf();
// set up for a null!!
// for objects is easy.
mbnc.pushNull(javaReturnType);
mbnc.startElseCode();
if (!actualMethodReturnType.equals(javaReturnType))
mbnc.pushNewStart(javaReturnType);
// fetch all the arguments
for (int pa = 0; pa < nargs; pa++)
{
mbnc.getParameter(pa);
}
mbcm = mbnc;
}
mbcm.callMethod(VMOpcode.INVOKESTATIC, method.getDeclaringClass().getName(), methodName,
actualMethodReturnType, nargs);
if (returnsNullOnNullState != null)
{
// DERBY-3360. In the case of function returning
// a SMALLINT if we specify RETURN NULL ON NULL INPUT
// the javaReturnType will be java.lang.Integer. In
// order to initialize the integer properly, we need
// to upcast the short. This is a special case for
// SMALLINT functions only as other types are
// compatible with their function return types.
if (!actualMethodReturnType.equals(javaReturnType)) {
if (actualMethodReturnType.equals("short") &&
javaReturnType.equals("java.lang.Integer"))
mbnc.upCast("int");
mbnc.pushNewComplete(1);
}
mbnc.completeConditional();
mbnc.methodReturn();
mbnc.complete();
// now call the wrapper method
mb.callMethod(VMOpcode.INVOKEVIRTUAL, acb.getClassBuilder().getFullName(), mbnc.getName(),
javaReturnType, nargs);
mbnc = null;
}
if (routineInfo != null) {
// reset the SQL allowed setting that we set upon
// entry to the method.
if (functionEntrySQLAllowed != null) {
acb.pushThisAsActivation(mb);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
"getLanguageConnectionContext", ClassName.LanguageConnectionContext, 0);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
"getStatementContext", "org.apache.derby.iapi.sql.conn.StatementContext", 0);
mb.getField(functionEntrySQLAllowed);
mb.push(true); // override as we are ending the control set by this function all.
mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
"setSQLAllowed", "void", 2);
}
if (outParamArrays != null) {
MethodBuilder constructor = acb.getConstructor();
// constructor - setting up correct parameter type info
acb.pushThisAsActivation(constructor);
constructor.callMethod(VMOpcode.INVOKEINTERFACE, null,
"getParameterValueSet", ClassName.ParameterValueSet, 0);
// execute - passing out parameters back.
acb.pushThisAsActivation(mb);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
"getParameterValueSet", ClassName.ParameterValueSet, 0);
int[] parameterModes = routineInfo.getParameterModes();
for (int i = 0; i < outParamArrays.length; i++) {
int parameterMode = parameterModes[ getRoutineArgIdx( i ) ];
if (parameterMode != JDBC30Translation.PARAMETER_MODE_IN) {
// must be a parameter if it is INOUT or OUT.
ValueNode sqlParamNode = ((SQLToJavaValueNode) methodParms[i]).getSQLValueNode();
int applicationParameterNumber = applicationParameterNumbers[i];
// Set the correct parameter nodes in the ParameterValueSet at constructor time.
constructor.dup();
constructor.push(applicationParameterNumber);
constructor.push(parameterMode);
constructor.callMethod(VMOpcode.INVOKEINTERFACE, null,
"setParameterMode", "void", 2);
// Pass the value of the outparameters back to the calling code
LocalField lf = outParamArrays[i];
mb.dup();
mb.push(applicationParameterNumber);
mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
"getParameter", ClassName.DataValueDescriptor, 1);