[
https://issues.apache.org/jira/browse/DERBY-3823?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13126287#comment-13126287
]
Dag H. Wanvik commented on DERBY-3823:
--------------------------------------
Fiddling with your program I think the actual result set's getMetaData
is is correct (ResultSet#getMetaData) in the case I was worried about,
it appears it is read early on while processing the rs. (Sorry, I was
a bit mixed up here).
But your concern is *also* correct :) I changed the program to use an
*explicit* prepared statement (since the method for which we made the
patch is PreparedStatement#getMetaData) to retrieve metadata from
there, *as well as* getting the metadata from the actual result set.
The PreparedStatement's getMetaData method is described in this way in
the Javadoc:
"getMetaData() Retrieves a ResultSetMetaData object
that contains information about the columns of the ResultSet
object that *will be* returned when this PreparedStatement object
is executed." ("will be": my emphasis, not "just was".. ;-)
here is my run result (incl some trace from EmbedPreparedStatement#getMetaData)
Client/server:
$ java -cp .:$CLASSPATH DERBY3823StressTestNPE 2
execp.getResultDescription: insert into t1 values(?,'aaaaa')
execp.getResultDescription: insert into t1 values(?,'aaaaa')
Done loading data
execp.getResultDescription: select * from t1
execp.getResultDescription: select * from t1
executing alter
2. PS#getMetaData: char column length is 5
Reexecuting ps on changed table...
3. RS#getMetadata: char column length is 5
data:1 12345678
As we can see we are getting a value 8 long, but both ps's metadata
and rs's metadata are both out of date. Note that there is no new call
to execp.getResultDescription *after* we alter the table...
On embedded it is correct:
$ java -cp .:$CLASSPATH DERBY3823StressTestNPE
Done loading data
executing alter
execp.getResultDescription: select * from t1
2. PS#getMetaData: char column length is 8
Reexecuting ps on changed table...
3. RS#getMetadata: char column length is 8
data:1 12345678
As you observed, it should return 8. Maybe because it's cached on the
client side, but should have been invalidated. This looks like a bug
to me.
In any case, I think the patch improves the situation in that we now
will wait if the underlying prepared statement is being re-prepared. I
think we should file a new bug for this and relate it to the two you
mentioned. I can do it if you like. The current patch as least assures we get a
consistent
"snapshot" at the time metadata is attempted retrieved.
---------------------------------------------------
import java.sql.*;
public class DERBY3823StressTestNPE extends Thread {
public static void main(String[] args) throws Exception {
Connection conn = null;
if (args.length == 1) {
int embedded = Integer.parseInt(args[0]);
if (embedded == 1) {
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
conn = DriverManager.getConnection(
"jdbc:derby:DERBY3823DB;create=true");
} else {
Class.forName("org.apache.derby.jdbc.ClientDriver");
String url =
"jdbc:derby://localhost:1527/DERBY3823DB;create=true";
conn = DriverManager.getConnection(url);
}
} else {
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
conn = DriverManager.getConnection(
"jdbc:derby:DERBY3823DB;create=true");
}
conn.setAutoCommit(false);
Statement st = conn.createStatement();
st.executeUpdate("create table t1(c11 int, "+
"c12 varchar(5))");
{
PreparedStatement ps =
conn.prepareStatement("insert into t1 values(?,'aaaaa')");
for (int i = 0; i < 1000; i++) {
ps.setInt(1, i);
ps.executeUpdate();
}
}
System.out.println("Done loading data");
conn.commit();
PreparedStatement ps = conn.prepareStatement("select * from t1");
ResultSet rs = ps.executeQuery();
for (int i = 0; i < 990; i++) {
rs.next();
}
rs.close();
Statement st2 = conn.createStatement();
System.err.println("executing " + "alter");
st2.execute("alter table t1 alter column c12 set data type varchar(8)");
st2.execute("delete from t1");
st2.execute("insert into t1 values (1, '12345678')");
{
// Ps' javadoc: getMetaData() Retrieves a ResultSetMetaData object
// that contains information about the columns of the ResultSet
// object that *will be* returned when this PreparedStatement object
// is executed. (my emphasis)
ResultSetMetaData rsmd = ps.getMetaData();
int charLength = rsmd.getColumnDisplaySize(2);
System.out.println("2. PS#getMetaData: char column length is " +
charLength);
System.out.println("Reexecuting ps on changed table...");
rs = ps.executeQuery();
ResultSetMetaData rsmd2 = rs.getMetaData();
charLength = rsmd2.getColumnDisplaySize(2);
System.out.println("3. RS#getMetadata: char column length is " +
charLength);
while (rs.next()) {
System.out.println("data:" + rs.getString(1) + " " +
rs.getString(2));
}
rs.close();
}
}
}
> NullPointerException in stress.multi test
> -----------------------------------------
>
> Key: DERBY-3823
> URL: https://issues.apache.org/jira/browse/DERBY-3823
> Project: Derby
> Issue Type: Bug
> Components: Network Server
> Affects Versions: 10.3.3.1, 10.7.1.1, 10.8.1.2
> Reporter: Kathey Marsden
> Labels: derby_triage10_5_2
> Attachments: d3823-1.diff, derby.log
>
>
> I saw the following NPE in stress.multi running on 10.3 with derbyclient.
> java.lang.NullPointerException
> at
> org.apache.derby.impl.jdbc.EmbedPreparedStatement.getMetaData(Unknown
> Source)
> at org.apache.derby.impl.drda.DRDAConnThread.writeSQLDARD(Unknown
> Source
> )
> at org.apache.derby.impl.drda.DRDAConnThread.processCommands(Unknown
> Sou
> rce)
> at org.apache.derby.impl.drda.DRDAConnThread.run(Unknown Source)
> Cleanup action completed
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators:
https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira