From a473ff2ef14adfc32335c7053de40a5d97256949 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Fri, 2 May 2014 11:15:11 -0700 Subject: [PATCH] Make use of getGeneratedKeys in lastInsertedId. This allows us to do the necessary hackery for MySQL which reports the generated key as GENERATED_KEY instead of via its actual column name. --- .../java/com/samskivert/jdbc/BaseLiaison.java | 16 ++++++++++++++-- .../com/samskivert/jdbc/DatabaseLiaison.java | 10 +++++++++- .../java/com/samskivert/jdbc/DefaultLiaison.java | 7 ------- .../java/com/samskivert/jdbc/HsqldbLiaison.java | 6 +++++- .../java/com/samskivert/jdbc/JORARepository.java | 4 ++-- .../java/com/samskivert/jdbc/MySQLLiaison.java | 9 ++++++++- .../com/samskivert/jdbc/PostgreSQLLiaison.java | 7 ++++++- .../servlet/JDBCTableSiteIdentifier.java | 2 +- .../samskivert/servlet/user/UserRepository.java | 2 +- 9 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/samskivert/jdbc/BaseLiaison.java b/src/main/java/com/samskivert/jdbc/BaseLiaison.java index 2b3dd4ab..1377f233 100644 --- a/src/main/java/com/samskivert/jdbc/BaseLiaison.java +++ b/src/main/java/com/samskivert/jdbc/BaseLiaison.java @@ -36,9 +36,21 @@ public abstract class BaseLiaison implements DatabaseLiaison // from DatabaseLiaison public abstract boolean isTransientException (SQLException sqe); + @Deprecated + public int lastInsertedId (Connection conn, String table, String column) throws SQLException { + return lastInsertedId(conn, null, table, column); + } + // from DatabaseLiaison - public abstract int lastInsertedId (Connection conn, String table, String column) - throws SQLException; + public int lastInsertedId (Connection conn, Statement istmt, String table, String column) + throws SQLException + { + // if this JDBC driver supports getGeneratedKeys, use it! + if (istmt != null && conn.getMetaData().supportsGetGeneratedKeys()) { + return istmt.getGeneratedKeys().getInt(column); + } + return -1; + } // from DatabaseLiaison public boolean tableExists (Connection conn, String name) throws SQLException diff --git a/src/main/java/com/samskivert/jdbc/DatabaseLiaison.java b/src/main/java/com/samskivert/jdbc/DatabaseLiaison.java index 8ef1751a..dbb759da 100644 --- a/src/main/java/com/samskivert/jdbc/DatabaseLiaison.java +++ b/src/main/java/com/samskivert/jdbc/DatabaseLiaison.java @@ -5,6 +5,7 @@ package com.samskivert.jdbc; +import java.sql.Statement; import java.sql.Connection; import java.sql.SQLException; import java.util.List; @@ -43,12 +44,19 @@ public interface DatabaseLiaison */ public boolean isTransientException (SQLException sqe); + /** @deprecated Use version that takes the insert statement. */ + @Deprecated + public int lastInsertedId (Connection conn, String table, String column) throws SQLException; + /** * Attempts as dialect-agnostic an interface as possible to the ability of certain databases to * auto-generated numerical values for i.e. key columns; there is MySQL's AUTO_INCREMENT and * PostgreSQL's DEFAULT nextval(sequence), for example. + * + * @param istmt the insert statement that generated the keys. May be null if the ORM doesn't + * have the statement handy. */ - public int lastInsertedId (Connection conn, String table, String column) + public int lastInsertedId (Connection conn, Statement istmt, String table, String column) throws SQLException; /** diff --git a/src/main/java/com/samskivert/jdbc/DefaultLiaison.java b/src/main/java/com/samskivert/jdbc/DefaultLiaison.java index c763b18a..404c8f8a 100644 --- a/src/main/java/com/samskivert/jdbc/DefaultLiaison.java +++ b/src/main/java/com/samskivert/jdbc/DefaultLiaison.java @@ -46,13 +46,6 @@ public class DefaultLiaison extends BaseLiaison // nothing doing } - @Override // from DatabaseLiaison - public int lastInsertedId (Connection conn, String table, String column) - throws SQLException - { - return -1; - } - @Override // from DatabaseLiaison public String columnSQL (String column) { diff --git a/src/main/java/com/samskivert/jdbc/HsqldbLiaison.java b/src/main/java/com/samskivert/jdbc/HsqldbLiaison.java index 1aeb7b1a..970705b3 100644 --- a/src/main/java/com/samskivert/jdbc/HsqldbLiaison.java +++ b/src/main/java/com/samskivert/jdbc/HsqldbLiaison.java @@ -73,8 +73,12 @@ public class HsqldbLiaison extends BaseLiaison } @Override // from DatabaseLiaison - public int lastInsertedId (Connection conn, String table, String column) throws SQLException + public int lastInsertedId (Connection conn, Statement istmt, String table, String column) + throws SQLException { + int id = super.lastInsertedId(conn, istmt, table, column); + if (id >= 0) return id; + // HSQL does not keep track of per-table-and-column insertion data, so we are pretty much // going on blind faith here that we're fetching the right ID. In the overwhelming number // of cases that will be so, but it's still not pretty. diff --git a/src/main/java/com/samskivert/jdbc/JORARepository.java b/src/main/java/com/samskivert/jdbc/JORARepository.java index 9e509c10..da74a0f5 100644 --- a/src/main/java/com/samskivert/jdbc/JORARepository.java +++ b/src/main/java/com/samskivert/jdbc/JORARepository.java @@ -50,7 +50,7 @@ public abstract class JORARepository extends SimpleRepository throws SQLException, PersistenceException { table.insert(conn, object); - return liaison.lastInsertedId(conn, table.getName(), "TODO"); + return liaison.lastInsertedId(conn, null, table.getName(), "TODO"); } }); } @@ -250,7 +250,7 @@ public abstract class JORARepository extends SimpleRepository { if (table.update(conn, object) == 0) { table.insert(conn, object); - return liaison.lastInsertedId(conn, table.getName(), "TODO"); + return liaison.lastInsertedId(conn, null, table.getName(), "TODO"); } return -1; } diff --git a/src/main/java/com/samskivert/jdbc/MySQLLiaison.java b/src/main/java/com/samskivert/jdbc/MySQLLiaison.java index 29cff70a..2523e6ca 100644 --- a/src/main/java/com/samskivert/jdbc/MySQLLiaison.java +++ b/src/main/java/com/samskivert/jdbc/MySQLLiaison.java @@ -50,8 +50,15 @@ public class MySQLLiaison extends BaseLiaison } @Override // from DatabaseLiaison - public int lastInsertedId (Connection conn, String table, String column) throws SQLException + public int lastInsertedId (Connection conn, Statement istmt, String table, String column) + throws SQLException { + // MySQL hackily reports the last inserted key as GENERATED_KEY, so we call super with that + // "column name"; but if that doesn't work (we're using an old JDBC driver without support + // for returning generated keys), fall back to the old old method + int id = super.lastInsertedId(conn, istmt, table, "GENERATED_KEY"); + if (id >= 0) return id; + // MySQL does not keep track of per-table-and-column insertion data, so we are pretty much // going on blind faith here that we're fetching the right ID. In the overwhelming number // of cases that will be so, but it's still not pretty. diff --git a/src/main/java/com/samskivert/jdbc/PostgreSQLLiaison.java b/src/main/java/com/samskivert/jdbc/PostgreSQLLiaison.java index 25a8b0d3..c27c8ff7 100644 --- a/src/main/java/com/samskivert/jdbc/PostgreSQLLiaison.java +++ b/src/main/java/com/samskivert/jdbc/PostgreSQLLiaison.java @@ -35,8 +35,13 @@ public class PostgreSQLLiaison extends BaseLiaison } // from DatabaseLiaison - public int lastInsertedId (Connection conn, String table, String column) throws SQLException + public int lastInsertedId (Connection conn, Statement istmt, String table, String column) + throws SQLException { + // try the default first, which uses JDBC's getGeneratedKeys mechanism + int id = super.lastInsertedId(conn, istmt, table, column); + if (id >= 0) return id; + // PostgreSQL's support for auto-generated ID's comes in the form of appropriately named // sequences and DEFAULT nextval(sequence) modifiers in the ID columns. To get the next ID, // we use the currval() method which is set in a database sessions when any given sequence diff --git a/src/main/java/com/samskivert/servlet/JDBCTableSiteIdentifier.java b/src/main/java/com/samskivert/servlet/JDBCTableSiteIdentifier.java index 30d9377c..5a46b5fa 100644 --- a/src/main/java/com/samskivert/servlet/JDBCTableSiteIdentifier.java +++ b/src/main/java/com/samskivert/servlet/JDBCTableSiteIdentifier.java @@ -246,7 +246,7 @@ public class JDBCTableSiteIdentifier implements SiteIdentifier if (1 != stmt.executeUpdate()) { throw new PersistenceException("Not inserted " + site); } - site.siteId = liaison.lastInsertedId(conn, "sites", "siteId"); + site.siteId = liaison.lastInsertedId(conn, stmt, "sites", "siteId"); } finally { JDBCUtil.close(stmt); diff --git a/src/main/java/com/samskivert/servlet/user/UserRepository.java b/src/main/java/com/samskivert/servlet/user/UserRepository.java index 684ecb13..a2d7af0b 100644 --- a/src/main/java/com/samskivert/servlet/user/UserRepository.java +++ b/src/main/java/com/samskivert/servlet/user/UserRepository.java @@ -398,7 +398,7 @@ public class UserRepository extends JORARepository try { _utable.insert(conn, user); // update the userid now that it's known - user.userId = liaison.lastInsertedId(conn, _utable.getName(), "userId"); + user.userId = liaison.lastInsertedId(conn, null, _utable.getName(), "userId"); // nothing to return return null;