From a49015433404fdc3f68223fca0cc142568d6ca24 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Tue, 9 Oct 2018 22:53:49 -0400 Subject: [PATCH] Fix QueryMapper toResultSet and insertGetGeneratedKeyType to use PreparedStatementFactory and become un-ambiguous --- .../jdbc/CachingQueryMapper.java | 69 ++++-------------- .../moparisthebest/jdbc/ListQueryMapper.java | 13 ++-- .../moparisthebest/jdbc/NullQueryMapper.java | 18 ++--- .../jdbc/PreparedStatementFactory.java | 9 +++ .../com/moparisthebest/jdbc/QueryMapper.java | 72 +++++++++++-------- 5 files changed, 74 insertions(+), 107 deletions(-) create mode 100644 querymapper/src/main/java/com/moparisthebest/jdbc/PreparedStatementFactory.java diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/CachingQueryMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/CachingQueryMapper.java index 5408afa..2865c7d 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/CachingQueryMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/CachingQueryMapper.java @@ -93,47 +93,19 @@ public class CachingQueryMapper extends QueryMapper { } protected PreparedStatement getPreparedStatement(String sql) throws SQLException { - return getPreparedStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - } - - protected PreparedStatement getPreparedStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - PreparedStatement ps = cache.get(sql); - if (ps == null) { - //System.out.println("cache miss"); - ps = conn.prepareStatement(sql,resultSetType,resultSetConcurrency); - cache.put(sql, ps); - } - //else System.out.println("cache hit"); - return ps; + return getPreparedStatement(sql, defaultPsf); } - protected PreparedStatement getInsertPreparedStatement(final String sql, final int autoGeneratedKeys) throws SQLException { + /** + * This could perhaps end up caching something it shouldn't, as psf could return a different PreparedStatement + * for a given sql, we are going to assume this would never happen, if it could, don't use CachingQueryMapper or + * override this method, whatever you want. + */ + protected PreparedStatement getPreparedStatement(final String sql, final PreparedStatementFactory psf) throws SQLException { PreparedStatement ps = cache.get(sql); if (ps == null) { //System.out.println("cache miss"); - ps = conn.prepareStatement(sql, autoGeneratedKeys); - cache.put(sql, ps); - } - //else System.out.println("cache hit"); - return ps; - } - - protected PreparedStatement getInsertPreparedStatement(final String sql, final int[] columnIndexes) throws SQLException { - PreparedStatement ps = cache.get(sql); - if (ps == null) { - //System.out.println("cache miss"); - ps = conn.prepareStatement(sql, columnIndexes); - cache.put(sql, ps); - } - //else System.out.println("cache hit"); - return ps; - } - - protected PreparedStatement getInsertPreparedStatement(final String sql, final String[] columnNames) throws SQLException { - PreparedStatement ps = cache.get(sql); - if (ps == null) { - //System.out.println("cache miss"); - ps = conn.prepareStatement(sql, columnNames); + ps = psf.prepareStatement(conn, sql); cache.put(sql, ps); } //else System.out.println("cache hit"); @@ -171,34 +143,19 @@ public class CachingQueryMapper extends QueryMapper { @Override public Long insertGetGeneratedKey(String sql, Object... bindObjects) throws SQLException { - return super.insertGetGeneratedKey(getInsertPreparedStatement(sql, Statement.RETURN_GENERATED_KEYS), bindObjects); + return super.insertGetGeneratedKey(getPreparedStatement(sql, getSingleColumnPreparedStatementFactory()), bindObjects); } @Override - public T insertGetGeneratedKeyType(String sql, TypeReference typeReference, Object... bindObjects) throws SQLException { - return super.insertGetGeneratedKeyType(getInsertPreparedStatement(sql, Statement.RETURN_GENERATED_KEYS), typeReference, bindObjects); - } - - @Override - public T insertGetGeneratedKeyType(String sql, int[] columnIndexes, TypeReference typeReference, Object... bindObjects) throws SQLException { - return super.insertGetGeneratedKeyType(getInsertPreparedStatement(sql, columnIndexes), typeReference, bindObjects); - } - - @Override - public T insertGetGeneratedKeyType(String sql, String[] columnNames, TypeReference typeReference, Object... bindObjects) throws SQLException { - return super.insertGetGeneratedKeyType(getInsertPreparedStatement(sql, columnNames), typeReference, bindObjects); + public T insertGetGeneratedKeyType(String sql, final PreparedStatementFactory psf, TypeReference typeReference, Object... bindObjects) throws SQLException { + return super.insertGetGeneratedKeyType(getPreparedStatement(sql, psf), typeReference, bindObjects); } // these grab ResultSets from the database - - @Override - public ResultSet toResultSet(String sql, Object... bindObjects) throws SQLException { - return super.toResultSet(getPreparedStatement(sql), bindObjects); - } @Override - public ResultSet toResultSet(String sql, int rsType, int rsConcurrency, Object... bindObjects) throws SQLException { - return super.toResultSet(getPreparedStatement(sql,rsType,rsConcurrency), bindObjects); + public ResultSet toResultSet(final String sql, final PreparedStatementFactory psf, final Object... bindObjects) throws SQLException { + return super.toResultSet(getPreparedStatement(sql, psf), bindObjects); } // DO NOT EDIT BELOW THIS LINE, OR CHANGE THIS COMMENT, CODE AUTOMATICALLY GENERATED BY genQueryMapper.sh diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java index 0ca4528..700c254 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java @@ -293,8 +293,8 @@ public class ListQueryMapper extends QueryMapper { } @Override - public ResultSet toResultSet(String sql, int rsType, int rsConcurrency, Object... bindObjects) throws SQLException { - return delegate.toResultSet(prepareSql(sql, bindObjects), rsType, rsConcurrency, bindObjects); + public ResultSet toResultSet(String sql, PreparedStatementFactory psf, Object... bindObjects) throws SQLException { + return delegate.toResultSet(prepareSql(sql, bindObjects), psf, bindObjects); } @Override @@ -308,13 +308,8 @@ public class ListQueryMapper extends QueryMapper { } @Override - public T insertGetGeneratedKeyType(String sql, int[] columnIndexes, TypeReference typeReference, Object... bindObjects) throws SQLException { - return delegate.insertGetGeneratedKeyType(prepareSql(sql, bindObjects), columnIndexes, typeReference, bindObjects); - } - - @Override - public T insertGetGeneratedKeyType(String sql, String[] columnNames, TypeReference typeReference, Object... bindObjects) throws SQLException { - return delegate.insertGetGeneratedKeyType(prepareSql(sql, bindObjects), columnNames, typeReference, bindObjects); + public T insertGetGeneratedKeyType(String sql, PreparedStatementFactory psf, TypeReference typeReference, Object... bindObjects) throws SQLException { + return delegate.insertGetGeneratedKeyType(prepareSql(sql, bindObjects), psf, typeReference, bindObjects); } // DO NOT EDIT BELOW THIS LINE, OR CHANGE THIS COMMENT, CODE AUTOMATICALLY GENERATED BY genQueryMapper.sh diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/NullQueryMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/NullQueryMapper.java index 2d5cdf5..eafc1be 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/NullQueryMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/NullQueryMapper.java @@ -165,19 +165,9 @@ public class NullQueryMapper extends QueryMapper { } @Override - public T insertGetGeneratedKeyType(String sql, int[] columnIndexes, TypeReference typeReference, Object... bindObjects) { + public T insertGetGeneratedKeyType(String sql, PreparedStatementFactory psf, TypeReference typeReference, Object... bindObjects) { try { - return delegate.insertGetGeneratedKeyType(sql, columnIndexes, typeReference, bindObjects); - } catch (Throwable e) { - if (verbose) e.printStackTrace(); - } - return null; - } - - @Override - public T insertGetGeneratedKeyType(String sql, String[] columnNames, TypeReference typeReference, Object... bindObjects) { - try { - return delegate.insertGetGeneratedKeyType(sql, columnNames, typeReference, bindObjects); + return delegate.insertGetGeneratedKeyType(sql, psf, typeReference, bindObjects); } catch (Throwable e) { if (verbose) e.printStackTrace(); } @@ -269,9 +259,9 @@ public class NullQueryMapper extends QueryMapper { } @Override - public ResultSet toResultSet(String sql, int rsType, int rsConcurrency, Object... bindObjects) throws SQLException { + public ResultSet toResultSet(String sql, PreparedStatementFactory psf, Object... bindObjects) { try { - return delegate.toResultSet(sql, rsType, rsConcurrency, bindObjects); + return delegate.toResultSet(sql, psf, bindObjects); } catch (Throwable e) { if (verbose) e.printStackTrace(); } diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/PreparedStatementFactory.java b/querymapper/src/main/java/com/moparisthebest/jdbc/PreparedStatementFactory.java new file mode 100644 index 0000000..8c9c316 --- /dev/null +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/PreparedStatementFactory.java @@ -0,0 +1,9 @@ +package com.moparisthebest.jdbc; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public interface PreparedStatementFactory { + PreparedStatement prepareStatement(Connection conn, String sql) throws SQLException; +} diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java index 4c6b3f0..c9cf5b4 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java @@ -25,7 +25,32 @@ public class QueryMapper implements JdbcMapper { protected static final int[] ORACLE_SINGLE_COLUMN_INDEX = new int[]{1}; + //IFJAVA8_START + public static final PreparedStatementFactory oracleSingleColumnPsf = (conn, sql) -> conn.prepareStatement(sql, ORACLE_SINGLE_COLUMN_INDEX); + public static final PreparedStatementFactory standardReturnGeneratedKeysPsf = (conn, sql) -> conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + public static final PreparedStatementFactory defaultPsf = Connection::prepareStatement; + //IFJAVA8_END + /*IFJAVA6_START + public static final PreparedStatementFactory oracleSingleColumnPsf = new PreparedStatementFactory() { + @Override + public PreparedStatement prepareStatement(Connection conn, String sql) throws SQLException { + return conn.prepareStatement(sql, ORACLE_SINGLE_COLUMN_INDEX); + } + }; + public static final PreparedStatementFactory standardReturnGeneratedKeysPsf = new PreparedStatementFactory() { + @Override + public PreparedStatement prepareStatement(Connection conn, String sql) throws SQLException { + return conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + } + }; + public static final PreparedStatementFactory defaultPsf = new PreparedStatementFactory() { + @Override + public PreparedStatement prepareStatement(Connection conn, String sql) throws SQLException { + return conn.prepareStatement(sql); + } + }; + private static final Charset UTF_8 = Charset.forName("UTF-8"); IFJAVA6_END*/ @@ -332,20 +357,27 @@ public class QueryMapper implements JdbcMapper { } } - private Boolean oracleDatabase = null; - public Long insertGetGeneratedKey(final String sql, final Object... bindObjects) throws SQLException { + private PreparedStatementFactory singleColumnPsf = null; + protected PreparedStatementFactory getSingleColumnPreparedStatementFactory() { // this single function is somewhat database specific // sqlite/ms-sql/mysql works with either Statement.RETURN_GENERATED_KEYS or int[]{1} // oracle requires int[]{1} instead, failing on Statement.RETURN_GENERATED_KEYS // postgre requires Statement.RETURN_GENERATED_KEYS instead, failing on int[]{1} // so we lazily cache oracleDatabase just in this one function - if(oracleDatabase == null) - oracleDatabase = OptimalInList.isWrapperFor(conn, OptimalInList.oracleConnection); + if(singleColumnPsf == null) { + if(OptimalInList.isWrapperFor(conn, OptimalInList.oracleConnection)) + singleColumnPsf = oracleSingleColumnPsf; + else + singleColumnPsf = standardReturnGeneratedKeysPsf; + } + return singleColumnPsf; + } + public Long insertGetGeneratedKey(final String sql, final Object... bindObjects) throws SQLException { PreparedStatement ps = null; try { - ps = oracleDatabase ? conn.prepareStatement(sql, ORACLE_SINGLE_COLUMN_INDEX) : conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + ps = getSingleColumnPreparedStatementFactory().prepareStatement(conn, sql); return this.insertGetGeneratedKey(ps, bindObjects); } finally { tryClose(ps); @@ -353,29 +385,13 @@ public class QueryMapper implements JdbcMapper { } public T insertGetGeneratedKeyType(final String sql, final TypeReference typeReference, final Object... bindObjects) throws SQLException { - PreparedStatement ps = null; - try { - ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); - return this.insertGetGeneratedKeyType(ps, typeReference, bindObjects); - } finally { - tryClose(ps); - } + return insertGetGeneratedKeyType(sql, standardReturnGeneratedKeysPsf, typeReference, bindObjects); } - public T insertGetGeneratedKeyType(final String sql, final int[] columnIndexes, final TypeReference typeReference, final Object... bindObjects) throws SQLException { + public T insertGetGeneratedKeyType(final String sql, final PreparedStatementFactory psf, final TypeReference typeReference, final Object... bindObjects) throws SQLException { PreparedStatement ps = null; try { - ps = conn.prepareStatement(sql, columnIndexes); - return this.insertGetGeneratedKeyType(ps, typeReference, bindObjects); - } finally { - tryClose(ps); - } - } - - public T insertGetGeneratedKeyType(final String sql, final String[] columnNames, final TypeReference typeReference, final Object... bindObjects) throws SQLException { - PreparedStatement ps = null; - try { - ps = conn.prepareStatement(sql, columnNames); + ps = psf.prepareStatement(conn, sql); return this.insertGetGeneratedKeyType(ps, typeReference, bindObjects); } finally { tryClose(ps); @@ -422,17 +438,17 @@ public class QueryMapper implements JdbcMapper { return bindExecute(ps, bindObjects); } - public ResultSet toResultSet(String sql, final Object... bindObjects) throws SQLException { - return toResultSet(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, bindObjects); + public ResultSet toResultSet(final String sql, final Object... bindObjects) throws SQLException { + return toResultSet(sql, defaultPsf, bindObjects); } - public ResultSet toResultSet(String sql, int rsType, int rsConcurrency, final Object... bindObjects) throws SQLException { + public ResultSet toResultSet(final String sql, final PreparedStatementFactory psf, final Object... bindObjects) throws SQLException { // works with StatementClosingResultSet boolean error = true; PreparedStatement ps = null; ResultSet rs = null; try { - ps = conn.prepareStatement(sql, rsType, rsConcurrency); + ps = psf.prepareStatement(conn, sql); rs = this.toResultSet(ps, bindObjects); error = false; return new StatementClosingResultSet(rs, ps);