Recent backward compatibility break in PreparedStatement.setObject()

From: Adam Rauch <adam(at)labkey(dot)com>
To: pgsql-jdbc(at)postgresql(dot)org
Subject: Recent backward compatibility break in PreparedStatement.setObject()
Date: 2015-12-30 21:45:17
Message-ID: 5684506D.4040006@labkey.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-jdbc

The PostgreSQL JDBC driver recently changed PreparedStatement behavior
with calls such as setObject(index, value, Types.VARCHAR). Previously,
the driver would call value.toString() before binding all VARCHAR
values... meaning any object could be passed as "value." In recent
updates (e.g., 9.4.1207), most non-String values now result in an exception:

Exception in thread "main" org.postgresql.util.PSQLException:
Cannot convert an instance of XXX to type String
at
org.postgresql.jdbc.PgStatement.cannotCastException(PgStatement.java:1813)
at
org.postgresql.jdbc.PgStatement.cannotCastException(PgStatement.java:1809)
at
org.postgresql.jdbc.PgStatement.castToString(PgStatement.java:1805)
at org.postgresql.jdbc.PgStatement.setObject(PgStatement.java:1540)
at org.postgresql.jdbc.PgStatement.setObject(PgStatement.java:1818)
at PGTest.main(PGTest.java:25)

This seems to have broken during the refactor to support binary transfer
for setObject(), https://github.com/pgjdbc/pgjdbc/issues/328. Was the
behavior change intentional? If so, it should probably be documented
(e.g., I didn't see any mention in the change log). If not, I'd suggest
going back to calling value.toString() for all types. I'm sure ours is
not the only application that relies on this long-standing (>10 years)
PostgreSQL JDBC behavior. FWIW, other JDBC drivers call toString() in
this situation.

Here's a contrived example that demonstrates the behavior change. This
code snippet runs fine in 1201 but fails with the exception above in 1207.

Object param =new Object() {public String toString() {return "tables";}};

try (PreparedStatement stmt = conn.prepareStatement("SELECT *FROM information_schema.tables WHERE table_name = ?"))
{
stmt.setObject(1, param, Types.VARCHAR);

try (ResultSet rs = stmt.executeQuery())
{
while (rs.next())
System.out.println(rs.getString(1));
}
}

Thanks,
Adam

Responses

Browse pgsql-jdbc by date

  From Date Subject
Next Message Dave Cramer 2015-12-30 21:54:40 Re: Recent backward compatibility break in PreparedStatement.setObject()
Previous Message Dave Cramer 2015-12-30 20:11:29 Re: Are pgrpm changes for JDBC discussed here before submission?