db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Mamta A. Satoor (JIRA)" <derby-...@db.apache.org>
Subject [jira] Updated: (DERBY-479) Passing the return of a RETURN NULL ON NULL INPUT function to another function call throws linkage error.
Date Mon, 13 Feb 2006 21:26:43 GMT
     [ http://issues.apache.org/jira/browse/DERBY-479?page=all ]

Mamta A. Satoor updated DERBY-479:
----------------------------------

    Attachment: Derby479LinkageErrorReturnNullIfNulldiff021306.txt

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.

> Passing the return of  a RETURN NULL ON NULL INPUT function to another function call
throws linkage error.
> ----------------------------------------------------------------------------------------------------------
>
>          Key: DERBY-479
>          URL: http://issues.apache.org/jira/browse/DERBY-479
>      Project: Derby
>         Type: Bug
>   Components: SQL
>     Versions: 10.2.0.0
>     Reporter: Daniel John Debrunner
>  Attachments: Derby479LinkageErrorReturnNullIfNulldiff021306.txt
>
> Error in ij (RN_RADIANS is a function declared as returns null on null input)
> ij> VALUES CAST( CALL_COS(RN_RADIANS(90.0)) AS DECIMAL(3,2));
> ERROR XBCM1: Java linkage error thrown during load of generated class org.apache.derby.exe.ace5214067x0105x5e41x7a46xffff855452e375.
> ERROR XJ001: Java exception: '(class: org/apache/derby/exe/ace5214067x0105x5e41x
> 7a46xffff855452e375, method: e0 signature: ()Ljava/lang/Object;) Expecting to find double
on stack: java.lang.VerifyError'.
> extract from derby.log
> 2005-07-28 16:23:43.836 GMT Thread[main,5,main] Wrote class org.apache.derby.exe
> .ace5214067x0105x5e41x7a46xffff855452e375 to file C:\_work\svn_pb\trunk\systest\
> out\functions\ace5214067x0105x5e41x7a46xffff855452e375.class. Please provide sup
> port with the file and the following exception information: java.lang.VerifyErro
> r: (class: org/apache/derby/exe/ace5214067x0105x5e41x7a46xffff855452e375, method
> : e0 signature: ()Ljava/lang/Object;) Expecting to find double on stack
> I will add a test case to lang/functions.sql commented with this bug number. Test cases
> that fail will be commented out.

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira


Mime
View raw message