I spent some time on this Jira entry and here is what I found.
When the sample program does rs.updateCharacterStream() on a Clob column, we generate a derby.client.am.Clob object with it's dataType_ as CHARACTER_STREAM
Thread [main] (Suspended)
Clob.<init>(Agent, Reader, int) line: 170
CrossConverters.setObject(int, Reader, int) line: 651
NetResultSet(ResultSet).updateCharacterStream(int, Reader, int) line: 3066
DERBY_1599_Repro.main(String) line: 56
In other words, the resultant derby.client.am.Clob object has a character stream associated with it but it's string_ variable is NULL.
Later, when the sample program retrieve the Clob object using
Clob clob = rs.getClob(1);
we get the Clob object with character stream associated with it but no direct string value. The return of Clob object for the call above is shown in the following call stack
Thread [main] (Suspended)
NetResultSet(ResultSet).getClob(int) line: 1256
DERBY_1599_Repro.main(String) line: 57
The problem happens for the next call in the user program when we try to use substring, ie
String string = clob.getSubString(1, (int) clob.length());
This is implemented in
derby.client.am.Clob.getSubStringX(long, int) line: 326
and the code for Clob.getSubStringX in derby network client looks as follows
private String getSubStringX(long pos, int length) throws SqlException
// actual length is the lesser of the length requested
// and the number of characters available from pos to the end
long actualLength = Math.min(this.sqlLength() - pos + 1, (long) length);
//Check to see if the Clob object is locator enabled.
//The Clob object is locator enabled. Hence call the stored
//procedure CLOBGETLENGTH to determine the length of the Clob.
.clobGetSubString(locator_, pos, (int)actualLength);
//The Clob object is not locator enabled.
((int) pos - 1, (int) (pos - 1 + actualLength));
Since this Clob object is not locator enabled, the code control goes to else in the code above and since string_ is NULL, we end up getting null pointer exception.
To fix the problem, should we be checking if string_ is null, and if yes, then check what stream is associated with the Clob object and then materialize the string_ from the stream? Would like to know if anyone has any thoughts on this.
BTW, I tried modifying the repro program so that we try to do
rs.updateCharacterStream(1, r, 3);
but that didn't go very well either. It resulted in following exception
$ java org.apache.derbyTesting.functionTests.tests.lang.DERBY_1599_Repro
Exception in thread "main" java.sql.SQLException: An attempt was made to put a data value of type 'java.sql.Clob' into a data value of type 'CHAR'.
Caused by: org.apache.derby.client.am.SqlException: An attempt was made to put a data value of type 'java.sql.Clob' into a data value of type 'CHAR'.
... 1 more