java: binding parameter values influences the result types you get from JDBC


JDBC lets you get the types of the parameters of a prepared statement, and the types of the result set, without actually executing the statement. That also works when you have bind parameters. But in this SQL statement, what are the types of the result set columns?

SELECT ?

The parameter could be literally anything! Even in this statement:

SELECT ? + 1

the types of the parameter and the result are arguably ambiguous (what if the parameter is NUMERIC? or DOUBLE PRECISION?).

It turns out the PostgreSQL JDBC driver, at least, just makes its best guess:

jshell> import java.sql.Connection;

jshell> import java.sql.DriverManager;

jshell> var conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/postgres?user=postgres&password=password");

jshell> var stmt = conn.prepareStatement("SELECT ?");
stmt ==> SELECT ?

jshell> var meta = stmt.getMetaData();
meta ==> org.postgresql.jdbc.PgResultSetMetaData@25bbf683

jshell> for (int i = 0; i < meta.getColumnCount(); i++) {
   ...>     System.out.println(meta.getColumnTypeName(i + 1));
   ...> }
text

Here you can see that PostgreSQL has just filled in “text” as its best guess as to the type. But of course, if you bound an integer, you’d get back an integer.

If you did have the actual parameter values, could you get the actual types of the result set columns, taking those parameter values into account? It turns out, yes, at least for the PostgreSQL JDBC driver! Just bind them and call getMetaData again:

jshell> stmt.setInt(1, 42);

jshell> meta = stmt.getMetaData();
meta ==> org.postgresql.jdbc.PgResultSetMetaData@401e7803

jshell> for (int i = 0; i < meta.getColumnCount(); i++) {
   ...>     System.out.println(meta.getColumnTypeName(i + 1));
   ...> }
int4