Search code examples
jdbcprepared-statementpostgresql-9.4jdbipg-jdbc

Pg-jdbc Appends RETURNING * on Prepared Batch wtih Existing RETURNING Clause


I am executing a prepared batch insert into a Postgres table using pg-jdbc/JDBI in order to obtain a list of generated id values using an explicit RETURNING clause:

PreparedBatch b = getHandle().prepareBatch("INSERT INTO death_star(id,exhaust_port) VALUES ( :id, :exhaust_port) RETURNING id;");

for (RebelPilot p : rebelPilots) {
    b.add().bind("id",p.getId()).bind("exhaust_port",p.getProtonTorpedo());
}

ResultSetMapper<Long> mapper = new IdMapper()
GeneratedKeys<Long> gk = b.executeAndGenerateKeys(mapper);
return gk.list()

When the statement is prepared, pg-jdbc will mindlessly append an extra RETURNING * after the existing RETURNING clause resulting in the following malformed abomination:

INSERT INTO death_star(id,exhaust_port) VALUES ( ?, ?) RETURNING id RETURNING *;

If I remove the explicit RETURNING clause, the statement works fine; however, it causes ALL fields from the target table to be returned, which is highly undesirable in many situations where large amounts of data have been inserted.

Is there any method to stop the pg-jdbc from engaging in this behavior?

Test Dependencies:

<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
  <version>9.4.1207.jre7</version>
</dependency>
<dependency>
  <groupId>org.jdbi</groupId>
  <artifactId>jdbi</artifactId>
  <version>2.71</version>
</dependency>

Solution

  • You are using executeAndGenerateKeys which will likely use Connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS). The generated keys implementation of PostgreSQL JDBC will append RETURNING * to the query in that case (it does not check if it already exists in the query text). You need to remove RETURNING id from your own query to make it work.

    If you want to use RETURNING id as some sort of optimization, then you need to find out if JDBI has an API to access Connection.preparedStatement(String query, String[] columnNames) (which as far as I can tell it doesn't have).

    To only other option is to file an improvement request for pgjdbc.