From fad614f85a589e6b1287040d9d81c37cabf035e5 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Wed, 26 Sep 2018 00:30:11 -0400 Subject: [PATCH] Partially implement PreparedStatement.getGeneratedKeys() returning long/Long in JdbcMapper --- .../jdbc/codegen/JdbcMapperProcessor.java | 34 +++++++++++++++++-- .../jdbc/codegen/PersonDAO.java | 6 ++++ .../jdbc/codegen/PrestoPersonDAO.java | 8 ++++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/JdbcMapperProcessor.java b/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/JdbcMapperProcessor.java index b0f321f..34f58c2 100644 --- a/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/JdbcMapperProcessor.java +++ b/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/JdbcMapperProcessor.java @@ -23,6 +23,7 @@ import java.util.stream.Stream; //IFJAVA8_END import static com.moparisthebest.jdbc.TryClose.tryClose; +import static com.moparisthebest.jdbc.codegen.JdbcMapper.DatabaseType.ORACLE; import static com.moparisthebest.jdbc.codegen.JdbcMapperFactory.SUFFIX; /** @@ -474,8 +475,9 @@ public class JdbcMapperProcessor extends AbstractProcessor { for (final SpecialVariableElement param : inListBindParams.values()) setArray(w, databaseType, arrayNumberTypeName, arrayStringTypeName, param); w.write("\t\t\tps = "); + final boolean isGeneratedKeyLong = !parsedSQl.isSelect() && (returnType.equals("long") || returnType.equals("java.lang.Long")); final boolean cachePreparedStatements = sql.cachePreparedStatement().combine(defaultCachePreparedStatements) && !bindInList; - if (cachePreparedStatements) { + if (cachePreparedStatements && !isGeneratedKeyLong) { // make isGeneratedKeyLong work with cachePreparedStatements w.write("this.prepareStatement("); w.write(Integer.toString(cachedPreparedStatements)); w.write(", "); @@ -487,7 +489,16 @@ public class JdbcMapperProcessor extends AbstractProcessor { w.write(sqlStatement.replace("\"", "\\\"") .replace("\n", "\\n\" +\n\t\t\t \"") .replace("REPLACEMEWITHUNQUOTEDQUOTEPLZ", "\"")); - w.write("\");\n"); + w.write("\""); + if(isGeneratedKeyLong) { + if(databaseType == ORACLE) { + // todo: cache this + w.write(", new int[]{1}"); + } else { + w.write(", java.sql.Statement.RETURN_GENERATED_KEYS"); + } + } + w.write(");\n"); // now bind parameters if(bindInList) { @@ -506,8 +517,25 @@ public class JdbcMapperProcessor extends AbstractProcessor { w.write("\t\t\tps.executeUpdate();\n"); } else if (returnType.equals("int") || returnType.equals("java.lang.Integer")) { w.write("\t\t\treturn ps.executeUpdate();\n"); + } else if (returnType.equals("boolean") || returnType.equals("java.lang.Boolean")) { + w.write("\t\t\treturn ps.executeUpdate() > 0;\n"); + } else if (isGeneratedKeyLong) { + w.write("\t\t\tps.executeUpdate();\n"); // todo: what about java8+ ps.executeLargeUpdate()? + w.write("\t\t\tResultSet rs = null;\n" + + "\t\t\ttry {\n" + + "\t\t\t\trs = ps.getGeneratedKeys();\n" + + "\t\t\t\treturn rs.next() ? "); + if(returnType.equals("long")) { + w.write("rs.getLong(1) : 0"); + } else { + w.write("com.moparisthebest.jdbc.util.ResultSetUtil.getObjectLong(rs, 1) : null"); + } + w.write(";\n" + + "\t\t\t} finally {\n" + + "\t\t\t\ttryClose(rs);\n" + + "\t\t\t}\n"); } else { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@JdbcMapper.SQL sql other than SELECT must return either void, int, or Integer", methodElement); + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@JdbcMapper.SQL sql other than SELECT must return either void, int, Integer, boolean, Boolean, long, or Long", methodElement); continue; } } else { diff --git a/test/src/main/java/com/moparisthebest/jdbc/codegen/PersonDAO.java b/test/src/main/java/com/moparisthebest/jdbc/codegen/PersonDAO.java index 127f69d..b476288 100644 --- a/test/src/main/java/com/moparisthebest/jdbc/codegen/PersonDAO.java +++ b/test/src/main/java/com/moparisthebest/jdbc/codegen/PersonDAO.java @@ -32,6 +32,12 @@ public interface PersonDAO extends JdbcMapper { @JdbcMapper.SQL("INSERT INTO person (person_no, birth_date, last_name, first_name) VALUES ({personNo}, {birthDate}, {firstName}, {lastName})") int insertPerson(long personNo, Date birthDate, String firstName, String lastName); + @JdbcMapper.SQL("INSERT INTO person (person_no, birth_date, last_name, first_name) VALUES ({personNo}, {birthDate}, {firstName}, {lastName})") + long insertPersonGeneratedKey(long personNo, Date birthDate, String firstName, String lastName); + + @JdbcMapper.SQL("INSERT INTO person (person_no, birth_date, last_name, first_name) VALUES ({personNo}, {birthDate}, {firstName}, {lastName})") + Long insertPersonGeneratedKeyLong(long personNo, Date birthDate, String firstName, String lastName); + @JdbcMapper.SQL("UPDATE person SET first_name = {firstName} WHERE last_name = {lastName}") int setFirstName(String firstName, String lastName); diff --git a/test/src/main/java/com/moparisthebest/jdbc/codegen/PrestoPersonDAO.java b/test/src/main/java/com/moparisthebest/jdbc/codegen/PrestoPersonDAO.java index 502dc42..5ca6f91 100644 --- a/test/src/main/java/com/moparisthebest/jdbc/codegen/PrestoPersonDAO.java +++ b/test/src/main/java/com/moparisthebest/jdbc/codegen/PrestoPersonDAO.java @@ -19,7 +19,7 @@ import java.time.*; */ @JdbcMapper.Mapper( jndiName = "bob", - databaseType = JdbcMapper.DatabaseType.ANY, // PrestoPersonDao breaks with ORACLE or UNNEST + databaseType = JdbcMapper.DatabaseType.ANY, // todo: PrestoPersonDao breaks with ORACLE or UNNEST cachePreparedStatements = JdbcMapper.OptionalBool.FALSE , sqlParser = PrestoSQLParser.class , allowReflection = JdbcMapper.OptionalBool.TRUE @@ -32,6 +32,12 @@ public interface PrestoPersonDAO extends PersonDAO { @JdbcMapper.SQL("INSERT INTO person (person_no, birth_date, last_name, first_name) VALUES ({personNo}, {birthDate}, {firstName}, {lastName})") int insertPerson(long personNo, Date birthDate, String firstName, String lastName); + @JdbcMapper.SQL("INSERT INTO person (person_no, birth_date, last_name, first_name) VALUES ({personNo}, {birthDate}, {firstName}, {lastName})") + long insertPersonGeneratedKey(long personNo, Date birthDate, String firstName, String lastName); + + @JdbcMapper.SQL("INSERT INTO person (person_no, birth_date, last_name, first_name) VALUES ({personNo}, {birthDate}, {firstName}, {lastName})") + Long insertPersonGeneratedKeyLong(long personNo, Date birthDate, String firstName, String lastName); + @JdbcMapper.SQL("UPDATE person SET first_name = {firstName} WHERE last_name = {lastName}") int setFirstName(String firstName, String lastName);