views:

32

answers:

2

The problem in a nutshell:

This is what happens when trying to insert a row with a few null columns using a prepared statement and groovy.sql.Sql:

groovy:000> val
===> [123123123, 2, null, 0, 0, , null, , 1213020112511801, 1283425009158952, 1, 2, null, 0, 0, , null, , 1213020112511801, 1283425009158952]
groovy:000> destSql.execute "insert into my_table values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", val
ERROR java.sql.SQLException: Type is not supported.
        at org.apache.derby.client.am.SQLExceptionFactory40.getSQLException (Unknown Source)
        at org.apache.derby.client.am.SqlException.getSQLException (Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.setObject (Unknown Source)
        at groovysh_evaluate.run (groovysh_evaluate:3)
        ...
groovy:000> 

I get a similar result with destSql.dataSet("my_table").add valueMap.

This is what happens when trying to insert the same row as a GString:

groovy:000> destSql.execute "insert into my_table values (${val[0]}, ${val[1]}, ${val[2]}, ${val[3]}, ${val[4]}, ${val[5]}, ${val[6]}, ${val[7]}, ${val[8]}, ${val[9]})"
===> false
groovy:000> 

Now, I understand that there are problems inserting null values using a prepared statement (as documented e.g. here and here).

What I would like to understand is the following:

1) I find it hard to believe that inserting nulls with prepared statements is impossible, so why does it sometimes cause problems? Less than perfect JDBC drivers, database engines?

2) Why does the example with the GString work? Following the same logic, doesn't it still type information even about the null columns, so how come it works?

A: 

the gstring example is working because the code ${val[0]} will return null if the array element is null.

if the code you inserted in the question is correct, some of you elements do not have a null value... this just a guess

Aaron Saunders
You can see the values I tried to insert: they represent a valid record with a couple of fields set to null. `${val[0]}` will indeed return null, but why does Derby accept that and not accept a null value as a parameter of a prepared statement?
Tomislav Nakic-Alfirevic
+1  A: 

You'll get better responses if you include the actual exception that you've encountered. You can find the exception in your Derby server's derby.log file, or you can also modify your application to print the entire exception chain, not just the client-side outermost exception: http://wiki.apache.org/db-derby/UnwindExceptionChain

Without seeing the actual exception, it's quite hard to help you, but I'll venture a guess that you're seeing https://issues.apache.org/jira/browse/DERBY-1938

Bryan Pendleton
That was an excellent link Bryan, I believe it explains well why the problem is intermittent (some combinations of driver, RDBMS and use pattern) and why using a prepared statement doesn't work in my case.
Tomislav Nakic-Alfirevic
Do you have an idea why the GStrings approach works? I skimmed over the groovy.sql.Sql source and saw it also tries to create a prepared statement...having passed it "Object" rather than "String" values, I can't imagine how it might work otherwise, yet derby would reject a prepared statement with a null value...?
Tomislav Nakic-Alfirevic
I'm pretty sure that, for a number of releases, PreparedStatement.setString(N, null) worked fine in Derby, but PreparedStatement.setObject(N, null) failed. This was the essence of the problem that DERBY-1938 fixed, I believe. So perhaps, depending on the exact data types that your Groovy program was using, the Groovy SQL library was sometimes calling setString, and other times calling setObject?
Bryan Pendleton
I wouldn't say that that's the probable cause, but I believe you've answered the other part of the riddle (why it doesn't work in my case) correctly so I'll wrap it up here.
Tomislav Nakic-Alfirevic