db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Daniel John Debrunner <...@apache.org>
Subject Re: [jira] Commented: (DERBY-479) Passing the return of a RETURN NULL ON NULL INPUT function to another function call throws linkage error.
Date Wed, 22 Feb 2006 19:33:40 GMT
Mamta A. Satoor (JIRA) wrote:

>     [ http://issues.apache.org/jira/browse/DERBY-479?page=comments#action_12367315 ]

> Mamta A. Satoor commented on DERBY-479:
> ---------------------------------------
> Dan, you are probably right about following 
>>>>>>>>>>Dan's review comments start
> "Looking more at StaticMethodCallNode.optimizeDomainValueConversion() I'm not convinced
it is correct. 
> The comments and code seem to say if I have 
>  f1(f2()) 
> then if f2() is CALLED ON NULL INPUT then I can take the java value directly from f2()
and pass it to f1(). 
> But, what if f1() is RETURNS NULL ON NULL INPUT, don't I need the SQL nodes to perform
the NULL check? 
> Thus don't both methods, the one being called and the one providing the parameter have
to be CALLED ON NULL INPUT to take allow the conversion nodes to be dropped? "
>>>>>>>>>>Dan's review comments end
> But I wanted to write an example for what you have described above to test what exactly
happens with my changes.
> Following is the example I came up with and it worked fine with my changes
> CREATE FUNCTION f2(A varchar(128)) RETURNS varchar(128)
> EXTERNAL NAME 'org.apache.derbyTesting.functionTests.util.ProcedureTest.function2AlwaysReturnsNull'
> CREATE FUNCTION f1(A varchar(128)) RETURNS varchar(128)
> EXTERNAL NAME 'org.apache.derbyTesting.functionTests.util.ProcedureTest.function1AlwaysReturnsAAA'
> The java methods invoked by the 2 sql functions are as follows
> 	public static String function1AlwaysReturnsAAA(String a) throws SQLException
> 	{
> 		return "AAA";
> 	}
> 	public static String function2AlwaysReturnsNull(String a) throws SQLException
> 	{
> 		return (String)null;
> 	}
> Then I tried following in ij and both of them returned null which is the correct value
> values f1(f2('sss'));
> 1
> --------------------------------------------------------------------------------
> values f1(f2(null));
> 1
> --------------------------------------------------------------------------------
> I have spent couple of hours on trying to come up with another example where I can see
that my changes won't work but I haven't succedded. Do you have an example in mind which I
can try? Thanks

To reset, the root cause of DERBY-479 is than an optimization is made
that is not applicable when a RETURNS NULL ON NULL INPUT function is

The optimization taking node constructs of the form :

 <java value> = SQL2Java (Java2SQL (<java value>) ) )

and replacing them with

   <java value> = <java value>

This optimization is made to avoid the cpu cost of performing a needless
conversion when the return of one Java method can be fed directly into
the argument of another Java method. It has its history in Cloudscape's
Java support in SQL, thus would take effect in situations like:

      values MyClass.fooS().bar() -- return of MyClass.fooS()
      values MyClass.hopS.bar() -- value of MyClass.hopS
      values foo().bar() -- return of foo()
      values foo().hop -- return of foo()
      values bar(foo()) -- return of foo()
      values bar(foo().hop) -- return of foo(), and value of foo().hop

The comment indicates which value is optimized to remain in the Java
domain (no conversion to and from SQL domain).

The problems are (introduced by me when implementing functions:-() is
when the construct is specifically:

 <outer method parameter java value>
            = SQL2Java (Java2SQL (<inner StaticMethodCall return value
>) ) )

DERBY-479 (linkage error)

Seen when the *inner* function is RETURNS NULL ON NULL INPUT

If the inner method returns a primitive value (Java int for SQL INTEGER)
then implementation for RETURNS NULL ON NULL INPUT changes the return
type of the <inner method java return value> from int to
java.lang.Integer. It adds some code in the StaticMethodCallNode to see
if the method should be called and create an java.lang.Integer() out of
the return value, or just return null.

The bug occurs when the SQL2Java and Java2SQL nodes are removed because
the StaticMethodCall probably continues to say it returns int, but it
returns Integer, thus causing code to be generated that passes a
java.lang.Integer to the outer method which is expecting a Java
primitive int.

Leaving the nodes fixes the issue as the Integer is successfully
converted to a SQLIntger and then a primitive int is obtained from the
SQLInteger (the conversion to and from SQL domain).

In retrospect I actually think there is a better fix, but it still
requires the logic not to remove these conversion nodes. I'll enter a
Jira for that as a separate issue.

Another bug, Related to DERBY-479 but not entered in Jira (i'll do
that). I think I just discovered this as a result of Mamta's question
and work on DERBY-479.

Seen when the *outer* function is RETURNS NULL ON NULL INPUT

If the outer method is for a RETURNS NULL ON NULL INPUT function then
the SQL2Java is the node performing the check to see if the argument is
NULL. Thus if this node is removed for this optimization then the outer
function will incorrectly behave as a CALLS NULL ON NULL INPUT function.


So Mamta's patch addresses the specific issue of DERBY-479 but I raised
the issue of it was not safe to remove these conversion nodes when the
*outer* function was RETURNS NULL ON NULL input, the patch only looks at
the type of the function generating the parameter value, not the
function being called with that parameter.

So why didn't Mamta's functions show the second bug, took a while to
realize this, but it's simple. For a function with a variable length
parameter the engine must insert a cast node to ensure that the value is
of the correct length. The engine cannot assume that the Java method for
a function that is declared to return VARCHAR(100) will return a String
with length <= 100, thus the nodes for Mamta's examples are like:

  <outer method parameter> = SQL2Java (CAST ( Java2SQL ( <inner methoo
return> ) ) )

thus the optimization can never take place, due to the CAST node.

The next obvious way to reproduce this was then with a INTEGER function,
but that doesn't work because we need the inner function to return null
in the Java domain to the outer function, but currently you can't define
a function that has a Java method with a return type of Integer.

So, to reproduce you need a fixed length SQL datatype that can use a
Java object type (to return null) for its method's return value. One
suitable type is TIME (java.sql.Time), I'll attach examples to the new
bug I'll enter in Jira. The bug reproduces with and without the patch,
namely an outer function is called when the inner function returns NULL,
even when the outer function is declared as RETURNS NULL ON NULL INPUT.


View raw message