Strange NullPointerException in result set checkColumnIndex

From: hack bear <hackingbear(at)hotmail(dot)com>
To: "pgsql-jdbc(at)postgresql(dot)org" <pgsql-jdbc(at)postgresql(dot)org>
Subject: Strange NullPointerException in result set checkColumnIndex
Date: 2013-07-19 19:39:25
Message-ID: BLU170-W70447CD015A7B65E3E80D1BA630@phx.gbl
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-jdbc

Hi,

I've been battling with a strange NullPointerException throwing out of PostgreSQL JDBC. Hope some genius can give me some help here. Thanks in advance!

This is roughly how the bug occurs

the code gets a connection from the apache-commons.dbcp BasicDataSourceit creates a PrepareStatement and executes a SELECT against some tables with UUID type column (the DB has implicit uuid to string cast via CREATE CAST(TEXT AS UUID) WITH INOUT AS IMPLICIT and CREATE CAST(VARCHAR AS UUID) WITH INOUT AS IMPLICIT)
the user gives a string "123213131321213123112" whicj is not a valid UUID format. the code set it to the statement via setString(1, "123213131321213123112")as expected, a SQLException is thrown: Caused by: org.postgresql.util.PSQLException: ERROR: invalid input syntax for uuid: "123213131321213123112"the code then call connection.close() properlyrepeat the above at least twice, serially or in parallel. same thingnow repeat the above with VALID UUID as inputcorrectly, the SQLException is NOT thrownthen code check result.next(), it returns true as expectedthe code then calls result.getString(1)BANG! a NullPointerException is thrown a shown below

Caused by: java.lang.NullPointerException: null
at org.postgresql.jdbc2.AbstractJdbc2ResultSet.checkColumnIndex(AbstractJdbc2ResultSet.java:2679) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.jdbc2.AbstractJdbc2ResultSet.checkResultSet(AbstractJdbc2ResultSet.java:2697) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.jdbc2.AbstractJdbc2ResultSet.getString(AbstractJdbc2ResultSet.java:1872) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.apache.commons.dbcp.DelegatingResultSet.getString(DelegatingResultSet.java:213) ~[commons-dbcp-1.4.jar:1.4]
at org.apache.commons.dbcp.DelegatingResultSet.getString(DelegatingResultSet.java:213) ~[commons-dbcp-1.4.jar:1.4]
at org.apache.commons.dbcp.DelegatingResultSet.getString(DelegatingResultSet.java:213) ~[commons-dbcp-1.4.jar:1.4]

Reproducibility and Environmentthe error is reproducible readily every time on the PostgreSQL 9.2 / RHEL 6. I would tend to rule out multithread errors in the code or the dbcp pool.but then I don't know why step 6 would be needed. (If I just make one request with invalid UUID and the another with valid one, the error does not occur)the dbcp is configued to setTestOnBorrow(true) but forgot to setValidateQuery(). However, setting the validate query to "select 1" does not help.try to force some other SQL error (like renaming the column) will NOT cause the subsequent NPE
the error never occurs in my local development environment on PostgreSQL 9.0.5 / MacOS X 10.7.5 not matter how many times I triedthe Postgres JDBC driver version is 9.1-901.jdbc4I wrote a simple test program imitating the same steps but it causes no error in those environments (my version has the real longer query the one shown here.)

Attachment: my test codes attempting to reproduce the problem

import org.apache.commons.dbcp.BasicDataSource;
import org.testng.annotations.Test;

import java.sql.*;

@Test(groups = {"auto"})
public class PostgressJDBCUUIDTest {
Connection dbc;
static BasicDataSource dataSource;
static {
dataSource = new BasicDataSource();
dataSource.setDefaultAutoCommit(false);
dataSource.setDefaultReadOnly(false);
dataSource.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setMaxActive(1);
dataSource.setMaxIdle(1);
dataSource.setMaxWait(10000); // 10 seconds max wait time
dataSource.setMinEvictableIdleTimeMillis(1 * 60 * 1000);
dataSource.setMinIdle(1);
dataSource.setPassword("");
dataSource.setPoolPreparedStatements(true);
dataSource.setTestOnBorrow(true); // this to make the connection safer, bookserve does this too
dataSource.setTestWhileIdle(false); // then no need to check while idle
// dataSource.setValidationQuery("select 1"); // doesn't seem to make a difference
dataSource.setUrl("jdbc:postgresql:blurb_development");
dataSource.setUsername("postgres");
}

@Test(enabled = true)
public void testOtherSQLError() throws Exception {
final String uuid = "927b8a04-c319-4139-b985-79b1cbc43871";
ResultSet result;
PreparedStatement stmt;
for (int i = 0; i < 10; i++) {
dbc = dataSource.getConnection();
try {
stmt = dbc.prepareStatement("select * from table_with_uuid where no_such_col = ?");
stmt.setString(1, "zzzzzzzzz");
result = stmt.executeQuery();
if (result.next()) {
String s = result.getString(1);
System.out.println("result: " + s);
} else {
System.out.println("no result");
}
result.close();
stmt.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
dbc.close();
}

System.out.println("----------------------------------------------------");
dbc = dataSource.getConnection();
stmt = dbc.prepareStatement("select * from table_with_uuid where uuid_col = ?");
stmt.setString(1, uuid);
result = stmt.executeQuery();
if (result.next()) {
String s = result.getString(1);
System.out.println("result: " + s);
} else {
System.out.println("no result");
}
result.close();
stmt.close();
dbc.close();
}

@Test
public void testUUIDSQLError() throws Exception {
System.out.println("***************************** ^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
ResultSet result;
PreparedStatement stmt;
for (int i = 0; i < 5; i++) {
dbc = dataSource.getConnection();
try {
String uuid = "92f0edb5-d155-4cf7-8af3-ef3194393ca5";
stmt = dbc.prepareStatement("select uuid_col from table_with_uuid where uuid_col = ?");
stmt.setString(1, uuid);
result = stmt.executeQuery();
if (result.next()) {
String s = result.getString(1);
System.out.println("result: " + s);
} else {
System.out.println("no result");
}
result.close();
stmt.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
dbc.close();
}

dbc = dataSource.getConnection();
System.out.println("----------------------------------------------------");

final String uuid = "927b8a04-c319-4139-b985-79b1cbc43871";
stmt = dbc.prepareStatement("select uuid_col from id2user where uuid_col = ?");
stmt.setString(1, uuid);
result = stmt.executeQuery();
if (result.next()) {
String s = result.getString(1);
System.out.println("result: " + s);
} else {
System.out.println("no result");
}
result.close();
stmt.close();
dbc.close();
}
}

Responses

Browse pgsql-jdbc by date

  From Date Subject
Next Message Sylvain Cuaz 2013-07-22 15:20:28 DatabaseMetaData getImportedKeys() order
Previous Message Tomonari Katsumata 2013-07-17 06:15:44 Re: a problem about setQueryTimeout is not fixed?