7

I'm using official JDBC driver for PostgreSQL, but I'm stuck with the following issues:

  • No support for PostgreSQL-ish data structures such as UUIDs.
  • Common JDBC weirdness, such as:
    • No function to escape values for consuming by PostgreSQL.
    • Limited support for executing heterogeneous statements in batch.
    • No rewriting of multiple insert statements into single insert statement when inserting many rows in one table.

So, the question — is there any PostgreSQL database driver which can leverage full power of PostgreSQL without much boilerplate? I'm also use Scala language for development, so if driver is designed specifically for Scala it would be so much awesome awesome.

andreypopp
  • 6,887
  • 5
  • 26
  • 26
  • 7
    Shouldn't any escaping be handled for you by using a `PreparedStatement` and setting values in it? A batch update won't work for inserting many rows? – ColinD Feb 04 '11 at 16:18
  • What exactly do you mean with: *No function to escape values for consuming* –  Feb 04 '11 at 16:26
  • @ColinD It's ok for homogeneous statements, but I'm also need to execute heterogeneous statements in batch and Statement.addBatch can accepts only SQL statements as String, not as another statement. – andreypopp Feb 04 '11 at 17:06
  • @a_horse_with_no_name Escape "I'm" into E'I\'m'. See above comment for explaining why I need such functionality. – andreypopp Feb 04 '11 at 17:08
  • 1
    @andreypopp: I honestly don't know what you're trying to do as far as the batch thing, and as far as string escaping... `PreparedStatement.setString` should handle any escaping for you. That's the point. – ColinD Feb 04 '11 at 17:29
  • 1
    @andreypopp: Escaping single quotes is precisely what a PreparedStatement will do for you. Regarding addBatch(): I don't understand what you mean with "heterogeneous statements" if you have different statements anyway (e.g. different tables) you will not be able to take advantage of PostgreSQL's multi row inserts as well. –  Feb 04 '11 at 17:46

5 Answers5

10

Some of this seems to be (unless I'm not understanding) user error in using JDBC. JDBC is a pretty ugly API, so never ask if you can do it elegantly, just ask if you can do it at all.

Escaping and inserting multiple rows should be handled, as @ColinD and @a_horse pointed out, with Prepared statements and batch operations. Under the hood, I would expect a good JDBC implementation to do the things you want (I am not familiar with PostgreSQL's implementation).

Regarding UUIDs, here is a solution:

All that PostgreSQL can do is convert string literals to uuid.

You can make use of this by using the data type org.postgresql.util.PGobject, which is a general class used to represent data types unknown to JDBC.

You can define a helper class:

public class UUID extends org.postgresql.util.PGobject {
    public static final long serialVersionUID = 668353936136517917L;
    public UUID(String s) throws java.sql.SQLException {
        super();
        this.setType("uuid");
        this.setValue(s);
    }
}

Then the following piece of code will succeed:

 java.sql.PreparedStatement stmt =
 conn.prepareStatement("UPDATE t SET uid = ? WHERE id = 1");
 stmt.setObject(1, new UUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"));
 stmt.executeUpdate();
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Yishai
  • 90,445
  • 31
  • 189
  • 263
  • Thanks for providing example for registering own types handles, but other issues are still unresolved for me. – andreypopp Feb 04 '11 at 17:15
4

The driver supports batched statements to speed up bulk inserts.

And using batched statements is a lot more portable than using proprietary INSERT syntax (and as far as I can tell, there is no big different between a multi-row insert and batched inserts)

Check out PreparedStatement.addBatch()

The reason why UUID is not supported is probably that UUID is not part of the Postgres core, just a contrib module.

Edit
Regarding the execute heterogeneous statements

The Postgres driver does support different types of statements in the a batch.

The following works fine:

Connection con = DriverManager.getConnection("jdbc:postgresql://localhost/postgres", "foo", "bar");
con.setAutoCommit(false);
Statement stmt = con.createStatement();
stmt.addBatch("create table foo (id integer, data varchar(100))");
stmt.addBatch("insert into foo values (1, 'one')");
stmt.addBatch("insert into foo values (2, 'two')");
stmt.addBatch("update foo set data = 'one_other' where id = 1");
stmt.executeBatch();
con.commit();

Although you do lose the automatic escaping that PreparedStatement gives you.

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
3

I realise this doesn't answer your entire question, but hopefully it will be useful all the same.

I'm using Java 6 and Postgres 8.4. The driver I'm using is in my Maven POM file as:

<dependency>
    <groupId>postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>8.4-702.jdbc4</version>
</dependency>

I'm using PreparedStatement.getObject() and PreparedStatement.setObject() with Java's java.util.UUID class to retrieve and store UUIDs.

For example:

pstm.setObject(1, guid); //where pstm is a PreparedStatement and guid is a UUID

and:

//where rs is a ResultSet
UUID myGuid = (UUID) rs.getObject("my_uuid_column_name"); 

Works fine.

With newer drivers, the following is alsow supported

UUID myGuid = rs.getObject("my_uuid_column_name", UUID.class); 
Brian Beckett
  • 4,742
  • 6
  • 33
  • 52
  • I've noticed that the Postgres JDBC driver seems to support `java.util.UUID` through `getObject()` and `setObject()` methods. Is this documented somewhere? – Lukas Eder Jan 05 '13 at 08:55
1

No support for PostgreSQL-ish data structures such as UUIDs.

On the contrary, the current JDBC driver (9.2-1002 JDBC 4) for Postgres 9.x does indeed support UUID via the setObject and getObject commands. You cannot get any more direct or simpler than that (in any database, Postgres or any other) because JDBC does not recognize UUID as a data type.

As far as I can tell, there is no need to create a helper class as suggest in another answer by Yishai.

No need to do any casting or go through strings.

enter image description here

See my blog post for more discussion and code example.

Code example excerpt:

java.util.UUID uuid = java.util.UUID.randomUUID();
…
preparedStatement.setObject( nthPlaceholder++, uuid ); // Pass UUID to database.
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • That's great, but it doesn't always seem to work: http://stackoverflow.com/questions/17969431/postgres-uuid-jdbc-not-working – user340535 Jul 31 '13 at 11:59
  • @user340535 Unfortunately, that question you link to is useless. No source code, detail, or context is provided, so no conclusion can be drawn. On the other hand, you can run my source code posted in this answer and posted in my linked blog post. It has run consistently without problems for me. – Basil Bourque Nov 03 '13 at 09:56
0

Take a look at O/R Broker, which is a Scala JDBC-based library for relational database access.

nilskp
  • 3,097
  • 1
  • 30
  • 34