You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-dev@db.apache.org by Mamta Satoor <ms...@gmail.com> on 2006/02/13 22:24:37 UTC

[PATCH] Derby-479 Passing the return of a RETURN NULL ON NULL INPUT function to another function call throws linkage error.

Hi,

I have a patch for this bug. The patch description in brief is as follows.

I have taken an example to explain the patch. Consider following sql
function.(Notice it is defined with RETURNS NULL ON NULL INPUT)

CREATE FUNCTION RN_abs(A int) RETURNS int
EXTERNAL NAME 'java.lang.Math.abs(int)'
RETURNS NULL ON NULL INPUT
LANGUAGE JAVA PARAMETER STYLE JAVA;
VALUES CAST( RN_abS(RN_abs(90)) AS INTEGER);

First let's start out by a VALUES query that does work fine.
VALUES RN_abs(90)

During the bind phase of VALUES RN_abs(90), following nodes are created
JavaToSQL ( StaticMethodCall (SQLToJava (NumericConstantNode for constant
90) ) )

During code generation, StaticMethodCallNode, for each of the parameters,
calls generateOneParameter. In this eg, there is only one parameter and the
node for that parameter is SQLToJavaValueNode. This node first generates the
SQL value by calling generate on NumericConstantNode. NumericConstantNode
generates code to get NumberDataValue for constant 90. This is the right
type for the SQL domain but since this needs to be passed into Java domain,
we need to do some casting. The java domain value would be to get a
primitive int from NumberDataValue. To achieve this, SQLToJavaValueNode in
it's generateJavaValue generates the code to get primitive value from
NumberDataValue. In this case, it will be generating code to call getInt()
on NumberDataValue so that we have the correct type for the java domain.

StaticMethodCallNode after generating each parameter checks if the argument
type to SQL function is same
as the parameter type to the Java method. In this case, the SQL argument
type is java.lang.Integer and Java method parameter type is int. Because of
this, it casts the item on the top of the stack to Java method parameter
type.

After taking care of parameter code generation, StaticMethodCallNode checks
if the sql function is defined to return null if any of its arguments are
null. This is true for our specific sql function. To take care of this,
StaticMethodNode needs to have a return type of Object rather than primitive
int type. After generating code to call java.lang.Math.abs, it generates the
code to return java.lang.Math.abs's return value as java.lang.Integer This
is where VALUES ( RN_abS(RN_abs(90))) runs into problem.

So, now let's look at the problem sql.
VALUES ( RN_abS(RN_abs(90)));

In the bind phase, following nodes are created for VALUES (
RN_abS(RN_abs(90)))
JavaToSQL ( StaticMethodCall ( StaticMethodCall (SQLToJava
(NumericConstantNode for constant 90) ) )  )

In generate phase, SQLToJavaValueNode generates code for SQL domain
NumberDataValue first. But since the value needs to be returned to Java
domain, it generates code to call getInt on NumberDataValue to get int for
the Java domain. The inside StaticMethodCallNode finds that SQL function
argument type is not same as Java parameter type and hence it generates code
to cast the stack value to Java method parameter type. StaticMethodNode then
generates the code to call java.lang.Math.abs and it converts the int type
of the Java method return value into java.lang.Integer because the sql
function has been defined to return null on null input. In order to be able
to return null, the return type can't be primitive, it has to be an Object
which in this case is java.lang.Integer. So far the code generation is same
as for simple VALUES RN_abs(90). The problem happens during code generation
for outside StaticMethodCallNode. Outside StaticMethodCallNode is expecting
an int type but inside StaticMethodNode returned java.lang.Integer to cover
return null on null state definition of the sql function. This type mismatch
is what causes the linkage exception.

I have resolved this type mismatch for outside sql function call by
retrieving int value from java.lang.Integer with the help of the
DataValueFactory, as shown below (I have added the code for this in
MethodCallNode.generateParameters. The new code has !!! in front of them in
following code)
   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)) {
!!!     //The type on the stack for this parameter will not be primitive if
this parameter
!!!     //is a call to another sql function which is defined to return null
on null input.
!!!     //To take care of such a case, first generate the code to extract
primitive type
!!!     //from the value on the top of the stack. Derby479. eg
!!!     //CREATE FUNCTION RN_abs(A int) RETURNS int
!!!     //EXTERNAL NAME 'java.lang.Math.abs(int)'
!!!     //RETURNS NULL ON NULL INPUT
!!!     //LANGUAGE JAVA PARAMETER STYLE JAVA;
!!!     //VALUES ( RN_abS(RN_abs(90)));
!!!     //Inside RN_abs is returning a java.lang.Math so that it can return
null if the argument
!!!     //to it is null. But inside RN_abS is expecting primitive type int
as input argument.
!!!     //Following piece of code extract primitive value from the Object
value.
!!!     TypeId temp =
methodParms[param].getJSQLType().getSQLType().getTypeId();
!!!     acb.generateDataValue(mb, getTypeCompiler(temp), (LocalField) null);
!!!     mb.callMethod(VMOpcode.INVOKEINTERFACE,
ClassName.DataValueDescriptor,
!!!       getTypeCompiler(temp).getPrimitiveMethodName(),
!!!       getTypeCompiler(temp).getCorrespondingPrimitiveTypeName(), 0);
     mb.cast(parameterType);
    } else {
Because of these changes to MethodCallNode, mb.cast doesn't run into casting
exception anymore. I have attached the code changes to the JIRA entry.

svn stat
M
java\engine\org\apache\derby\impl\sql\compile\ActivationClassBuilder.java
M      java\engine\org\apache\derby\impl\sql\compile\MethodCallNode.java
M      java\engine\org\apache\derby\impl\sql\compile\CursorNode.java
M      java\engine\org\apache\derby\impl\sql\compile\SQLToJavaValueNode.java
M
java\testing\org\apache\derbyTesting\functionTests\tests\lang\functions.sql
M
java\testing\org\apache\derbyTesting\functionTests\master\functions.out

I ran derbyall on my Windows XP with Sun's jdk14 and everything ran fine.

Please send any feedback you might have.

Mamta

Re: [PATCH] Derby-479 Passing the return of a RETURN NULL ON NULL INPUT function to another function call throws linkage error.

Posted by Daniel John Debrunner <dj...@apache.org>.
Mamta Satoor wrote:

> Please find my replies inline. Hopefully they answer your questions.
> 
> On 2/13/06, *Daniel John Debrunner* <djd@apache.org

I think the confusion is arising out of the fact that because this is a
nested call the return of one method/function is fed into the argument
of the other. In such cases it helps to be very clear about what exactly
is being explained.

> So, getParameterTypeName returns the type as "java.lang.Integer" to generateParameters at line 536.
> generateParameters compares this type with the type of the Java method which is "int",
>line 541. Since they don't match, on line 549, it does casting of the top
> of the stack to the Java method type. The inside StaticMethodCallNode
> finds the top of stack to be "int" type already (because NumberDataValue's 
> returns int as it's Java primitive value) and hence the casting done on 549
> for inside StaticMethodCallNode, although a no-op, is not a problem.
> But in the case of the outside StaticMethodCallNode, on line 549,
> it finds that the top of the stack is of the type java.lang.Integer
> (because of return null on null input), the casting on line 549
> fails for outside StaticMethodCallNode because it is trying to java.lang.Integer to int.
> I hope this explanation is helpful.

This is good, with your earlier description I think I was confused by an
abrupt change from describing what happens with the inner parameter to
what you were seeing with the outer parameter. Without telling the
reader you are describing something else it becomes hard to understand.

> 
>     I thought the generated code was something like this for a parameter in
>     an returns null on null input function.
> 
>       DataValueDescriptor pdvd = <somthing>
> 
>       if (pdvd.isNull())
>           forceReturnNull = true; // actually generated field name
>       else
>           // needed due to limitation in byte code compiler
>           forceReturnNull = forceReturnNull;
> 
>       int pInner = pdvd.getInt();
> 
>     See SQLToJavaValueNode.generateReturnsNullOnNullCheck()
> 
>  
> You are right about what gets generated, which is primitive int type, at
> this point. But the conversion of int to java.lang.Integer happens after
> all the parameters code generation is finished.

The above code fragment shows the code generated for the inner call
(that takes the constant 90 in this case). Thus the engine takes a SQL
type (NumberDataValue internal representation) and gets a primitive int
from it.

This primitive int parameter is never converted to a java.lang.Integer.

When you say 'But the conversion of int to java.lang.Integer happens
after all the parameters code generation is finished', it is not
occuring for the parameter to the inner call. That int value is not
coverted to a java.lang.Integer.

The return of the inner call does undergo a conversion of int to
java.lang.Integer, the line numbers you give in StaticMethodCallNode
relate to the return value.

So the generated code for the inner call is something like:
(I added an 'int pInner =' to the above code fragment to link it to this)

   Integer innerFunctionVal;
   if (forceReturnNull)
       innerFunctionVal= null;
   else {
       innerFunctionVal= new Integer(Math.abs(pInner));
   }

Then, because the call to the outer method was short circuited directly
into java, we hit the bug, converting from an Integer to an int,
corresponding to the line numbers you gave in MethodCallNode, generating
code like:
(following on from previous fragment)

   // Due to the casts generated by MethodCallNode
   // *BUG* here - casting Integer to an int.
   int pOuter = (int) innerFunctionVal;

   Integer outerFunctionVal;
   if (forceReturnNull)
       outerFunctionVal= null;
   else {
       outerFunctionVal= new Integer(Math.abs(pOuter));
   }


I'm glad that not removing the SQL2Java and Java2SQL nodes seemed to fix
the issue.

Dan.


Re: [PATCH] Derby-479 Passing the return of a RETURN NULL ON NULL INPUT function to another function call throws linkage error.

Posted by Mamta Satoor <ms...@gmail.com>.
Please find my replies inline. Hopefully they answer your questions.

On 2/13/06, Daniel John Debrunner <dj...@apache.org> wrote:

> Mamta Satoor wrote:
> > Hi,
> >
> > I have a patch for this bug. The patch description in brief is as
> follows.
>
> Thanks for the full description.
>
> >
> > I have taken an example to explain the patch. Consider following sql
> > function.(Notice it is defined with RETURNS NULL ON NULL INPUT)
> >
> > CREATE FUNCTION RN_abs(A int) RETURNS int
> > EXTERNAL NAME 'java.lang.Math.abs(int)'
> > RETURNS NULL ON NULL INPUT
> > LANGUAGE JAVA PARAMETER STYLE JAVA;
> > VALUES CAST( RN_abS(RN_abs(90)) AS INTEGER);
> >
> > First let's start out by a VALUES query that does work fine.
> > VALUES RN_abs(90)
> >
> > During the bind phase of VALUES RN_abs(90), following nodes are created
> > JavaToSQL ( StaticMethodCall (SQLToJava (NumericConstantNode for
> > constant 90) ) )
> >
> > During code generation, StaticMethodCallNode, for each of the
> > parameters, calls generateOneParameter. In this eg, there is only one
> > parameter and the node for that parameter is SQLToJavaValueNode. This
> > node first generates the SQL value by calling generate on
> > NumericConstantNode. NumericConstantNode generates code to get
> > NumberDataValue for constant 90. This is the right type for the SQL
> > domain but since this needs to be passed into Java domain, we need to do
> > some casting. The java domain value would be to get a primitive int from
> > NumberDataValue. To achieve this, SQLToJavaValueNode in it's
> > generateJavaValue generates the code to get primitive value from
> > NumberDataValue. In this case, it will be generating code to call
> > getInt() on NumberDataValue so that we have the correct type for the
> > java domain.
> >
> > StaticMethodCallNode after generating each parameter checks if the
> > argument type to SQL function is same
> > as the parameter type to the Java method. In this case, the SQL argument
> > type is java.lang.Integer and Java method parameter type is int. Because
> > of this, it casts the item on the top of the stack to Java method
> > parameter type.
>
> I got lost in this paragraph. What do you mean by 'the SQL argument type
> is java.lang.Integer ...'? In the previous paragraph you said the
> SQLToJavaValueNode got the primitive directly from the NumberDataValue,
> so I'm lost as to where java.lang.Integer comes into it.
> Could you maybe point to the methods/line numbers where you think this
> is happening?


My comment was based on code MethodCallNode.generateParameters() line
numbers 535 through 549 as shown below

   // 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 {

In the same MethodCallNode class, getParameterTypeName is defined as follows

 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;
 }

So, getParameterTypeName returns the type as "java.lang.Integer" to
generateParameters at line 536. generateParameters compares this type with
the type of the Java method which is "int", line 541. Since they don't
match, on line 549, it does casting of the top of the stack to the Java
method type. The inside StaticMethodCallNode finds the top of stack to be
"int" type already (because NumberDataValue's  returns int as it's Java
primitive value) and hence the casting done on 549 for inside
StaticMethodCallNode, although a no-op, is not a problem. But in the case of
the outside StaticMethodCallNode, on line 549, it finds that the top of the
stack is of the type java.lang.Integer (because of return null on null
input), the casting on line 549 fails for outside StaticMethodCallNode
because it is trying to java.lang.Integer to int. I hope this explanation is
helpful.

> I thought the generated code was something like this for a parameter in
> an returns null on null input function.
>
>   DataValueDescriptor pdvd = <somthing>
>
>   if (pdvd.isNull())
>       forceReturnNull = true; // actually generated field name
>   else
>       // needed due to limitation in byte code compiler
>       forceReturnNull = forceReturnNull;
>
>   pdvd.getInt();
>
> See SQLToJavaValueNode.generateReturnsNullOnNullCheck()


You are right about what gets generated, which is primitive int type, at
this point. But the conversion of int to java.lang.Integer happens after all
the parameters code generation is finished.
StaitcMethodCallNode.generationExpression line numbers 892 through 922 and
lines 928 through 942 convert int type to java.lang.Integer if sql function
is defined with return null on null input. And that is why we end up with
java.lang.Integer.


> > After taking care of parameter code generation, StaticMethodCallNode
> > checks if the sql function is defined to return null if any of its
> > arguments are null. This is true for our specific sql function. To take
> > care of this, StaticMethodNode needs to have a return type of Object
> > rather than primitive int type. After generating code to call
> > java.lang.Math.abs, it generates the code to return java.lang.Math.abs's
> > return value as java.lang.Integer This is where VALUES (
> > RN_abS(RN_abs(90))) runs into problem.
> >
> > So, now let's look at the problem sql.
> > VALUES ( RN_abS(RN_abs(90)));
> >
> > In the bind phase, following nodes are created for VALUES (
> > RN_abS(RN_abs(90)))
> > JavaToSQL ( StaticMethodCall ( StaticMethodCall (SQLToJava
> > (NumericConstantNode for constant 90) ) )  )
>
> Just to check, this is really the case, the outer node StaticMethodCall
> wraps the inner one directly? Have the SQL2Java and Java2SQL nodes that
> were generated been removed? I think this might be the problem, they
> should not have been removed, because the returns null on null input
> really means that part of the function call executes in the SQL domain,
> and cannot be short cut by using its return in a direct call to Java
> method.


Yes, during the parsing phase, MethodCallNode.addParams(Vector) on lines 217
through 220 removes SQL2Java and Java2SQL and your guess is right about that
being the problem. When I removed that optimization by commenting out lines
217 through 221, the VALUES (RN_abS(RN_abs(90))) runs fine. I ran derbyall
with this change (and removed by changes that I had proposed in my earlier
mail) and the tests ran fine.

> In generate phase, SQLToJavaValueNode generates code for SQL domain
> NumberDataValue first. But since the value needs to be returned to Java
> domain, it generates code to call getInt on NumberDataValue to get int
> for the Java domain. The inside StaticMethodCallNode finds that SQL
> function argument type is not same as Java parameter type and hence it
> generates code to cast the stack value to Java method parameter type.
Same as above, I can't see this in the code.

> StaticMethodNode then generates the code to call java.lang.Math.abs and
> it converts the int type of the Java method return value into
> java.lang.Integer because the sql function has been defined to return
> null on null input. In order to be able to return null, the return type
> can't be primitive, it has to be an Object which in this case is
> java.lang.Integer. So far the code generation is same as for simple
> VALUES RN_abs(90). The problem happens during code generation for
> outside StaticMethodCallNode. Outside StaticMethodCallNode is expecting
> an int type but inside StaticMethodNode returned java.lang.Integer to
> cover return null on null state definition of the sql function. This
> type mismatch is what causes the linkage exception.

The question is why is the StaticMethodNode expecting an int type when
the return type is Integer?

> I have resolved this type mismatch for outside sql function call by
> retrieving int value from java.lang.Integer with the help of the
> DataValueFactory, as shown below (I have added the code for this in
> MethodCallNode.generateParameters .

What happens when the return from the inner function was null with your
change? Is the outer method called? I think you need some tests with
this case. I think the patch does not fix the problem.

Dan.

> The new code has !!! in front of
> them in following code)
>    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)) {
> !!!     //The type on the stack for this parameter will not be primitive
> if this parameter
> !!!     //is a call to another sql function which is defined to return
> null on null input.
> !!!     //To take care of such a case, first generate the code to
> extract primitive type
> !!!     //from the value on the top of the stack. Derby479. eg
> !!!     //CREATE FUNCTION RN_abs(A int) RETURNS int
> !!!     //EXTERNAL NAME 'java.lang.Math.abs(int)'
> !!!     //RETURNS NULL ON NULL INPUT
> !!!     //LANGUAGE JAVA PARAMETER STYLE JAVA;
> !!!     //VALUES ( RN_abS(RN_abs(90)));
> !!!     //Inside RN_abs is returning a java.lang.Math so that it can
> return null if the argument
> !!!     //to it is null. But inside RN_abS is expecting primitive type
> int as input argument.
> !!!     //Following piece of code extract primitive value from the
> Object value.
> !!!     TypeId temp =
> methodParms[param].getJSQLType().getSQLType().getTypeId();
> !!!     acb.generateDataValue(mb, getTypeCompiler(temp), (LocalField)
null);
> !!!     mb.callMethod(VMOpcode.INVOKEINTERFACE,
> ClassName.DataValueDescriptor ,
> !!!       getTypeCompiler(temp).getPrimitiveMethodName(),
> !!!       getTypeCompiler(temp).getCorrespondingPrimitiveTypeName(), 0);
>      mb.cast(parameterType);
>     } else {
> Because of these changes to MethodCallNode, mb.cast doesn't run into
> casting exception anymore. I have attached the code changes to the JIRA
> entry.
>
> svn stat
> M
> java\engine\org\apache\derby\impl\sql\compile\ActivationClassBuilder.java
> M      java\engine\org\apache\derby\impl\sql\compile\MethodCallNode.java
> M      java\engine\org\apache\derby\impl\sql\compile\CursorNode.java
>
M      java\engine\org\apache\derby\impl\sql\compile\SQLToJavaValueNode.java
> M
>
java\testing\org\apache\derbyTesting\functionTests\tests\lang\functions.sql
> M
> java\testing\org\apache\derbyTesting\functionTests\master\functions.out
>
> I ran derbyall on my Windows XP with Sun's jdk14 and everything ran fine.
>
> Please send any feedback you might have.
>
> Mamta
>

Re: [PATCH] Derby-479 Passing the return of a RETURN NULL ON NULL INPUT function to another function call throws linkage error.

Posted by Daniel John Debrunner <dj...@apache.org>.
Mamta Satoor wrote:
> Hi,
> 
> I have a patch for this bug. The patch description in brief is as follows.

Thanks for the full description.

> 
> I have taken an example to explain the patch. Consider following sql
> function.(Notice it is defined with RETURNS NULL ON NULL INPUT)
> 
> CREATE FUNCTION RN_abs(A int) RETURNS int
> EXTERNAL NAME 'java.lang.Math.abs(int)'
> RETURNS NULL ON NULL INPUT
> LANGUAGE JAVA PARAMETER STYLE JAVA;
> VALUES CAST( RN_abS(RN_abs(90)) AS INTEGER);
> 
> First let's start out by a VALUES query that does work fine.
> VALUES RN_abs(90)
> 
> During the bind phase of VALUES RN_abs(90), following nodes are created
> JavaToSQL ( StaticMethodCall (SQLToJava (NumericConstantNode for
> constant 90) ) )
> 
> During code generation, StaticMethodCallNode, for each of the
> parameters, calls generateOneParameter. In this eg, there is only one
> parameter and the node for that parameter is SQLToJavaValueNode. This
> node first generates the SQL value by calling generate on
> NumericConstantNode. NumericConstantNode generates code to get
> NumberDataValue for constant 90. This is the right type for the SQL
> domain but since this needs to be passed into Java domain, we need to do
> some casting. The java domain value would be to get a primitive int from
> NumberDataValue. To achieve this, SQLToJavaValueNode in it's
> generateJavaValue generates the code to get primitive value from
> NumberDataValue. In this case, it will be generating code to call
> getInt() on NumberDataValue so that we have the correct type for the
> java domain.
> 
> StaticMethodCallNode after generating each parameter checks if the
> argument type to SQL function is same
> as the parameter type to the Java method. In this case, the SQL argument
> type is java.lang.Integer and Java method parameter type is int. Because
> of this, it casts the item on the top of the stack to Java method
> parameter type.

I got lost in this paragraph. What do you mean by 'the SQL argument type
is java.lang.Integer ...'? In the previous paragraph you said the
SQLToJavaValueNode got the primitive directly from the NumberDataValue,
so I'm lost as to where java.lang.Integer comes into it.
Could you maybe point to the methods/line numbers where you think this
is happening?

I thought the generated code was something like this for a parameter in
an returns null on null input function.

   DataValueDescriptor pdvd = <somthing>

   if (pdvd.isNull())
       forceReturnNull = true; // actually generated field name
   else
       // needed due to limitation in byte code compiler
       forceReturnNull = forceReturnNull;

   pdvd.getInt();

See SQLToJavaValueNode.generateReturnsNullOnNullCheck()


> After taking care of parameter code generation, StaticMethodCallNode
> checks if the sql function is defined to return null if any of its
> arguments are null. This is true for our specific sql function. To take
> care of this, StaticMethodNode needs to have a return type of Object
> rather than primitive int type. After generating code to call
> java.lang.Math.abs, it generates the code to return java.lang.Math.abs's
> return value as java.lang.Integer This is where VALUES (
> RN_abS(RN_abs(90))) runs into problem.
> 
> So, now let's look at the problem sql.
> VALUES ( RN_abS(RN_abs(90)));
> 
> In the bind phase, following nodes are created for VALUES (
> RN_abS(RN_abs(90)))
> JavaToSQL ( StaticMethodCall ( StaticMethodCall (SQLToJava
> (NumericConstantNode for constant 90) ) )  )

Just to check, this is really the case, the outer node StaticMethodCall
wraps the inner one directly? Have the SQL2Java and Java2SQL nodes that
were generated been removed? I think this might be the problem, they
should not have been removed, because the returns null on null input
really means that part of the function call executes in the SQL domain,
and cannot be short cut by using its return in a direct call to Java method.

> In generate phase, SQLToJavaValueNode generates code for SQL domain
> NumberDataValue first. But since the value needs to be returned to Java
> domain, it generates code to call getInt on NumberDataValue to get int
> for the Java domain. The inside StaticMethodCallNode finds that SQL
> function argument type is not same as Java parameter type and hence it
> generates code to cast the stack value to Java method parameter type.
Same as above, I can't see this in the code.


> StaticMethodNode then generates the code to call java.lang.Math.abs and
> it converts the int type of the Java method return value into
> java.lang.Integer because the sql function has been defined to return
> null on null input. In order to be able to return null, the return type
> can't be primitive, it has to be an Object which in this case is
> java.lang.Integer. So far the code generation is same as for simple
> VALUES RN_abs(90). The problem happens during code generation for
> outside StaticMethodCallNode. Outside StaticMethodCallNode is expecting
> an int type but inside StaticMethodNode returned java.lang.Integer to
> cover return null on null state definition of the sql function. This
> type mismatch is what causes the linkage exception.

The question is why is the StaticMethodNode expecting an int type when
the return type is Integer?

> I have resolved this type mismatch for outside sql function call by
> retrieving int value from java.lang.Integer with the help of the
> DataValueFactory, as shown below (I have added the code for this in
> MethodCallNode.generateParameters . 

What happens when the return from the inner function was null with your
change? Is the outer method called? I think you need some tests with
this case. I think the patch does not fix the problem.

Dan.

> The new code has !!! in front of
> them in following code)
>    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)) {
> !!!     //The type on the stack for this parameter will not be primitive
> if this parameter
> !!!     //is a call to another sql function which is defined to return
> null on null input.
> !!!     //To take care of such a case, first generate the code to
> extract primitive type
> !!!     //from the value on the top of the stack. Derby479. eg
> !!!     //CREATE FUNCTION RN_abs(A int) RETURNS int
> !!!     //EXTERNAL NAME 'java.lang.Math.abs(int)'
> !!!     //RETURNS NULL ON NULL INPUT
> !!!     //LANGUAGE JAVA PARAMETER STYLE JAVA;
> !!!     //VALUES ( RN_abS(RN_abs(90)));
> !!!     //Inside RN_abs is returning a java.lang.Math so that it can
> return null if the argument
> !!!     //to it is null. But inside RN_abS is expecting primitive type
> int as input argument.
> !!!     //Following piece of code extract primitive value from the
> Object value.
> !!!     TypeId temp =
> methodParms[param].getJSQLType().getSQLType().getTypeId();
> !!!     acb.generateDataValue(mb, getTypeCompiler(temp), (LocalField) null);
> !!!     mb.callMethod(VMOpcode.INVOKEINTERFACE,
> ClassName.DataValueDescriptor ,
> !!!       getTypeCompiler(temp).getPrimitiveMethodName(),
> !!!       getTypeCompiler(temp).getCorrespondingPrimitiveTypeName(), 0);
>      mb.cast(parameterType);
>     } else {
> Because of these changes to MethodCallNode, mb.cast doesn't run into
> casting exception anymore. I have attached the code changes to the JIRA
> entry.
> 
> svn stat
> M     
> java\engine\org\apache\derby\impl\sql\compile\ActivationClassBuilder.java
> M      java\engine\org\apache\derby\impl\sql\compile\MethodCallNode.java
> M      java\engine\org\apache\derby\impl\sql\compile\CursorNode.java
> M      java\engine\org\apache\derby\impl\sql\compile\SQLToJavaValueNode.java
> M     
> java\testing\org\apache\derbyTesting\functionTests\tests\lang\functions.sql
> M     
> java\testing\org\apache\derbyTesting\functionTests\master\functions.out
> 
> I ran derbyall on my Windows XP with Sun's jdk14 and everything ran fine.
> 
> Please send any feedback you might have.
> 
> Mamta
>