summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Culkin <scorpress@gmail.com>2025-12-08 20:24:35 -0500
committerBenjamin Culkin <scorpress@gmail.com>2025-12-08 20:24:35 -0500
commita8adb94d009a65bbfc6985e833bf2d3510382a20 (patch)
treeed6ea7ca121a9f15f7e02c2c3413b6c7f4afc308
parentd68602dc425db4cb899830ad9058572c90622430 (diff)
Checkpoint commit for NamedPreparedStatement
The checkpoint is that I attempted to patch the version of NamedPreparedStatement I had to support building external batches. This... didn't really work right; though it initially appeared to do so. I am going to rewrite NamedPreparedStatement to actually properly support this functionality instead of half-arsing it
-rw-r--r--base/src/main/java/bjc/utils/misc/Binder.java8
-rw-r--r--base/src/main/java/bjc/utils/misc/BoundPreparedStatement.java456
-rw-r--r--base/src/main/java/bjc/utils/misc/NamedPreparedStatement.java499
-rw-r--r--base/src/main/java/bjc/utils/misc/ParamSnapshot.java33
4 files changed, 536 insertions, 460 deletions
diff --git a/base/src/main/java/bjc/utils/misc/Binder.java b/base/src/main/java/bjc/utils/misc/Binder.java
new file mode 100644
index 0000000..e657592
--- /dev/null
+++ b/base/src/main/java/bjc/utils/misc/Binder.java
@@ -0,0 +1,8 @@
+package bjc.utils.misc;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+@FunctionalInterface interface Binder {
+ void bind(PreparedStatement ps, int index) throws SQLException;
+} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/misc/BoundPreparedStatement.java b/base/src/main/java/bjc/utils/misc/BoundPreparedStatement.java
new file mode 100644
index 0000000..f87f4ec
--- /dev/null
+++ b/base/src/main/java/bjc/utils/misc/BoundPreparedStatement.java
@@ -0,0 +1,456 @@
+package bjc.utils.misc;
+
+import java.math.BigDecimal;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Parent class for {@link NamedPreparedStatement}
+ *
+ * Used mostly for cases where you want to prepare the bindings independently of the actual query.
+ */
+public class BoundPreparedStatement {
+ protected final Map<String, Binder> singles = new HashMap<>();
+ protected final Map<String, List<Binder>> lists = new HashMap<>();
+ protected final List<ParamSnapshot> batch = new ArrayList<>();
+
+ private static List<Binder> toBinders(Collection<?> values, int sqlType, boolean forceType) {
+ ArrayList<Binder> list = new ArrayList<>(values.size());
+ for (Object v : values) {
+ final Object val = v;
+ if (forceType) {
+ list.add((ps, i) -> {
+ if (val == null)
+ ps.setNull(i, sqlType);
+ else
+ ps.setObject(i, val, sqlType);
+ });
+ } else {
+ list.add((ps, i) -> ps.setObject(i, val));
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Record the current set of parameters as a batch and start a new one.
+ *
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement addBatch() {
+ batch.add(new ParamSnapshot(new HashMap<>(singles), deepCopyLists(lists)));
+ return this;
+ }
+
+ /**
+ * Clear the currently bound parameters.
+ *
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement clearParameters() {
+ singles.clear();
+ lists.clear();
+ return this;
+ }
+
+ /**
+ * Bind a object as a parameter
+ *
+ * @param name The name of the parameter
+ * @param value The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setObject(String name, Object value) {
+ singles.put(name, (ps, i) -> ps.setObject(i, value));
+ return this;
+ }
+
+ /**
+ * Bind a object as a parameter
+ *
+ * @param name The name of the parameter
+ * @param value The value for the parameter
+ * @param sqlType The SQL type for the parameter (see {@link java.sql.Types})
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setObject(String name, Object value, int sqlType) {
+ singles.put(name, (ps, i) -> {
+ if (value == null)
+ ps.setNull(i, sqlType);
+ else
+ ps.setObject(i, value, sqlType);
+ });
+ return this;
+ }
+
+ /**
+ * Bind a null as a parameter
+ *
+ * @param name The name of the parameter
+ * @param sqlType The SQL type for the parameter (see {@link java.sql.Types})
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setNull(String name, int sqlType) {
+ singles.put(name, (ps, i) -> ps.setNull(i, sqlType));
+ return this;
+ }
+
+ /**
+ * Bind a boolean as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setBoolean(String n, boolean x) {
+ singles.put(n, (ps, i) -> ps.setBoolean(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a byte as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setByte(String n, byte x) {
+ singles.put(n, (ps, i) -> ps.setByte(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a short as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setShort(String n, short x) {
+ singles.put(n, (ps, i) -> ps.setShort(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a int as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setInt(String n, int x) {
+ singles.put(n, (ps, i) -> ps.setInt(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a long as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setLong(String n, long x) {
+ singles.put(n, (ps, i) -> ps.setLong(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a float as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setFloat(String n, float x) {
+ singles.put(n, (ps, i) -> ps.setFloat(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a double as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setDouble(String n, double x) {
+ singles.put(n, (ps, i) -> ps.setDouble(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a {@link BigDecimal} as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setBigDecimal(String n, BigDecimal x) {
+ singles.put(n, (ps, i) -> ps.setBigDecimal(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a string as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setString(String n, String x) {
+ singles.put(n, (ps, i) -> ps.setString(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a byte-array as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setBytes(String n, byte[] x) {
+ singles.put(n, (ps, i) -> ps.setBytes(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a date as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setDate(String n, Date x) {
+ singles.put(n, (ps, i) -> ps.setDate(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a date as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @param c The calendar for the date
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setDate(String n, Date x, Calendar c) {
+ singles.put(n, (ps, i) -> ps.setDate(i, x, c));
+ return this;
+ }
+
+ /**
+ * Bind a time-value as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setTime(String n, Time x) {
+ singles.put(n, (ps, i) -> ps.setTime(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a time-value as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @param c The calendar for the time
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setTime(String n, Time x, Calendar c) {
+ singles.put(n, (ps, i) -> ps.setTime(i, x, c));
+ return this;
+ }
+
+ /**
+ * Bind a timestamp as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setTimestamp(String n, Timestamp x) {
+ singles.put(n, (ps, i) -> ps.setTimestamp(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a timestamp as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @param c The calendar for the timestamp
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setTimestamp(String n, Timestamp x, Calendar c) {
+ singles.put(n, (ps, i) -> ps.setTimestamp(i, x, c));
+ return this;
+ }
+
+ /**
+ * Bind a {@link Array} as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setArray(String n, Array x) {
+ singles.put(n, (ps, i) -> ps.setArray(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a {@link Blob} as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setBlob(String n, Blob x) {
+ singles.put(n, (ps, i) -> ps.setBlob(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a {@link Clob} as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setClob(String n, Clob x) {
+ singles.put(n, (ps, i) -> ps.setClob(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a URL as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setURL(String n, java.net.URL x) {
+ singles.put(n, (ps, i) -> ps.setURL(i, x));
+ return this;
+ }
+
+ /**
+ * Bind a ASCII stream as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @param len The length of the stream
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setAsciiStream(String n, java.io.InputStream x, int len) {
+ singles.put(n, (ps, i) -> ps.setAsciiStream(i, x, len));
+ return this;
+ }
+
+ /**
+ * Bind a binary stream as a parameter
+ *
+ * @param n The name of the parameter
+ * @param x The value for the parameter
+ * @param len The length of the stream
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setBinaryStream(String n, java.io.InputStream x, int len) {
+ singles.put(n, (ps, i) -> ps.setBinaryStream(i, x, len));
+ return this;
+ }
+
+ /**
+ * Bind a character stream as a parameter
+ *
+ * @param n The name of the parameter
+ * @param r The value for the parameter
+ * @param len The length of the stream
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setCharacterStream(String n, java.io.Reader r, int len) {
+ singles.put(n, (ps, i) -> ps.setCharacterStream(i, r, len));
+ return this;
+ }
+
+ /**
+ * Bind a list parameter to the statement
+ *
+ * @param name The name of the list parameter
+ * @param values The values for the list parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setList(String name, Collection<?> values) {
+ lists.put(name, toBinders(values, Types.OTHER, false));
+ return this;
+ }
+
+ /**
+ * Bind a list parameter to the statement
+ *
+ * @param name The name of the list parameter
+ * @param values The values for the list parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setList(String name, Object... values) {
+ lists.put(name, toBinders(Arrays.asList(values), Types.OTHER, false));
+ return this;
+ }
+
+ /**
+ * Explicit SQL type for all elements (useful if nulls might appear).
+ *
+ * @param name The name of the list parameter
+ * @param sqlType The SQL type for the parameters
+ * @param values The values for the list parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setList(String name, int sqlType, Collection<?> values) {
+ lists.put(name, toBinders(values, sqlType, true));
+ return this;
+ }
+
+ /**
+ * Explicit SQL type for all elements (useful if nulls might appear).
+ *
+ * @param name The name of the list parameter
+ * @param sqlType The SQL type for the parameters
+ * @param values The values for the list parameter
+ * @return The prepared statement
+ */
+ public BoundPreparedStatement setList(String name, int sqlType, Object... values) {
+ lists.put(name, toBinders(Arrays.asList(values), sqlType, true));
+ return this;
+ }
+
+ private static Map<String, List<Binder>> deepCopyLists(Map<String, List<Binder>> src) {
+ Map<String, List<Binder>> m = new HashMap<>(src.size());
+ for (Map.Entry<String, List<Binder>> e : src.entrySet()) {
+ m.put(e.getKey(), new ArrayList<>(e.getValue()));
+ }
+ return m;
+ }
+
+ /**
+ * Create a new {@link BoundPreparedStatement}
+ */
+ public BoundPreparedStatement() {
+
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/misc/NamedPreparedStatement.java b/base/src/main/java/bjc/utils/misc/NamedPreparedStatement.java
index b35029e..4389293 100644
--- a/base/src/main/java/bjc/utils/misc/NamedPreparedStatement.java
+++ b/base/src/main/java/bjc/utils/misc/NamedPreparedStatement.java
@@ -1,9 +1,8 @@
package bjc.utils.misc;
-import java.math.BigDecimal;
import java.sql.*;
-import java.sql.Date;
import java.util.*;
+import java.util.function.Function;
/**
* NamedPreparedStatement
@@ -30,8 +29,7 @@ import java.util.*;
* try (ResultSet rs = ps.executeQuery()) { ... }
* }
*/
-public final class NamedPreparedStatement implements AutoCloseable {
-
+public class NamedPreparedStatement extends BoundPreparedStatement implements AutoCloseable {
/* ---------- Construction ---------- */
private final Connection conn;
@@ -46,19 +44,13 @@ public final class NamedPreparedStatement implements AutoCloseable {
private PreparedStatement currentPs;
private String lastCompiledSql;
- // parameter values
- private final Map<String, Binder> singles = new HashMap<>();
- private final Map<String, List<Binder>> lists = new HashMap<>();
-
- // simple batch snapshots
- private final List<ParamSnapshot> batch = new ArrayList<>();
-
// empty-list behavior
private EmptyListMode emptyListMode = EmptyListMode.AS_NULL;
private String emptyListLiteral = "NULL";
private NamedPreparedStatement(Connection conn, String sql, Integer autoGeneratedKeys, Integer resultSetType,
Integer resultSetConcurrency) {
+ super();
this.conn = Objects.requireNonNull(conn, "conn");
this.originalSql = Objects.requireNonNull(sql, "sql");
this.tokens = parse(sql);
@@ -144,7 +136,7 @@ public final class NamedPreparedStatement implements AutoCloseable {
buildAndBind();
return currentPs;
}
-
+
/* ---------- Execution ---------- */
/**
@@ -209,26 +201,38 @@ public final class NamedPreparedStatement implements AutoCloseable {
}
/**
- * Record the current set of parameters as a batch and start a new one.
- *
- * @return The prepared statement
+ * Execute a batch from a recorded snapshot
+ * @param record
+ * @return The number of rows updated by each batch
+ * @throws SQLException
*/
- public NamedPreparedStatement addBatch() {
- batch.add(new ParamSnapshot(new HashMap<>(singles), deepCopyLists(lists)));
- return this;
- }
+ public List<Integer> executeBatchFromRecord(BoundPreparedStatement record) throws SQLException {
+ if (record.batch.isEmpty()) {
+ buildAndBind();
+ int[] batchRes = currentPs.executeBatch();
+ List<Integer> resList = new ArrayList<>(batchRes.length);
+ for (int i : batchRes) resList.add(i);
+ return resList;
+ }
+
+ List<Integer> counts = new ArrayList<>(batch.size());
+ List<Binder> binders = buildPreparedStatement(record);
- /**
- * Clear the currently bound parameters.
- *
- * @return The prepared statement
- */
- public NamedPreparedStatement clearParameters() {
- singles.clear();
- lists.clear();
- return this;
- }
+ for (ParamSnapshot snap : record.batch) {
+ // restore snapshot
+ this.singles.clear();
+ this.lists.clear();
+ this.singles.putAll(snap.singles);
+ this.lists.putAll(snap.lists);
+
+ bindPreparedStatement(binders);
+ counts.add(currentPs.executeUpdate());
+ }
+ record.batch.clear();
+ return counts;
+ }
+
/**
* Get the generated keys for this prepared statement.
*
@@ -298,381 +302,11 @@ public final class NamedPreparedStatement implements AutoCloseable {
/* ---------- Binding (single) ---------- */
- /**
- * Bind a object as a parameter
- *
- * @param name The name of the parameter
- * @param value The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setObject(String name, Object value) {
- singles.put(name, (ps, i) -> ps.setObject(i, value));
- return this;
- }
-
- /**
- * Bind a object as a parameter
- *
- * @param name The name of the parameter
- * @param value The value for the parameter
- * @param sqlType The SQL type for the parameter (see {@link java.sql.Types})
- * @return The prepared statement
- */
- public NamedPreparedStatement setObject(String name, Object value, int sqlType) {
- singles.put(name, (ps, i) -> {
- if (value == null)
- ps.setNull(i, sqlType);
- else
- ps.setObject(i, value, sqlType);
- });
- return this;
- }
- /**
- * Bind a null as a parameter
- *
- * @param name The name of the parameter
- * @param sqlType The SQL type for the parameter (see {@link java.sql.Types})
- * @return The prepared statement
- */
- public NamedPreparedStatement setNull(String name, int sqlType) {
- singles.put(name, (ps, i) -> ps.setNull(i, sqlType));
- return this;
- }
-
- /**
- * Bind a boolean as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setBoolean(String n, boolean x) {
- singles.put(n, (ps, i) -> ps.setBoolean(i, x));
- return this;
- }
-
- /**
- * Bind a byte as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setByte(String n, byte x) {
- singles.put(n, (ps, i) -> ps.setByte(i, x));
- return this;
- }
-
- /**
- * Bind a short as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setShort(String n, short x) {
- singles.put(n, (ps, i) -> ps.setShort(i, x));
- return this;
- }
-
- /**
- * Bind a int as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setInt(String n, int x) {
- singles.put(n, (ps, i) -> ps.setInt(i, x));
- return this;
- }
-
- /**
- * Bind a long as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setLong(String n, long x) {
- singles.put(n, (ps, i) -> ps.setLong(i, x));
- return this;
- }
-
- /**
- * Bind a float as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setFloat(String n, float x) {
- singles.put(n, (ps, i) -> ps.setFloat(i, x));
- return this;
- }
-
- /**
- * Bind a double as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setDouble(String n, double x) {
- singles.put(n, (ps, i) -> ps.setDouble(i, x));
- return this;
- }
-
- /**
- * Bind a {@link BigDecimal} as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setBigDecimal(String n, BigDecimal x) {
- singles.put(n, (ps, i) -> ps.setBigDecimal(i, x));
- return this;
- }
-
- /**
- * Bind a string as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setString(String n, String x) {
- singles.put(n, (ps, i) -> ps.setString(i, x));
- return this;
- }
-
- /**
- * Bind a byte-array as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setBytes(String n, byte[] x) {
- singles.put(n, (ps, i) -> ps.setBytes(i, x));
- return this;
- }
-
- /**
- * Bind a date as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setDate(String n, Date x) {
- singles.put(n, (ps, i) -> ps.setDate(i, x));
- return this;
- }
-
- /**
- * Bind a date as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @param c The calendar for the date
- * @return The prepared statement
- */
- public NamedPreparedStatement setDate(String n, Date x, Calendar c) {
- singles.put(n, (ps, i) -> ps.setDate(i, x, c));
- return this;
- }
-
- /**
- * Bind a time-value as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setTime(String n, Time x) {
- singles.put(n, (ps, i) -> ps.setTime(i, x));
- return this;
- }
-
- /**
- * Bind a time-value as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @param c The calendar for the time
- * @return The prepared statement
- */
- public NamedPreparedStatement setTime(String n, Time x, Calendar c) {
- singles.put(n, (ps, i) -> ps.setTime(i, x, c));
- return this;
- }
-
- /**
- * Bind a timestamp as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setTimestamp(String n, Timestamp x) {
- singles.put(n, (ps, i) -> ps.setTimestamp(i, x));
- return this;
- }
-
- /**
- * Bind a timestamp as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @param c The calendar for the timestamp
- * @return The prepared statement
- */
- public NamedPreparedStatement setTimestamp(String n, Timestamp x, Calendar c) {
- singles.put(n, (ps, i) -> ps.setTimestamp(i, x, c));
- return this;
- }
-
- /**
- * Bind a {@link Array} as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setArray(String n, Array x) {
- singles.put(n, (ps, i) -> ps.setArray(i, x));
- return this;
- }
-
- /**
- * Bind a {@link Blob} as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setBlob(String n, Blob x) {
- singles.put(n, (ps, i) -> ps.setBlob(i, x));
- return this;
- }
-
- /**
- * Bind a {@link Clob} as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setClob(String n, Clob x) {
- singles.put(n, (ps, i) -> ps.setClob(i, x));
- return this;
- }
-
- /**
- * Bind a URL as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setURL(String n, java.net.URL x) {
- singles.put(n, (ps, i) -> ps.setURL(i, x));
- return this;
- }
-
- /**
- * Bind a ASCII stream as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @param len The length of the stream
- * @return The prepared statement
- */
- public NamedPreparedStatement setAsciiStream(String n, java.io.InputStream x, int len) {
- singles.put(n, (ps, i) -> ps.setAsciiStream(i, x, len));
- return this;
- }
-
- /**
- * Bind a binary stream as a parameter
- *
- * @param n The name of the parameter
- * @param x The value for the parameter
- * @param len The length of the stream
- * @return The prepared statement
- */
- public NamedPreparedStatement setBinaryStream(String n, java.io.InputStream x, int len) {
- singles.put(n, (ps, i) -> ps.setBinaryStream(i, x, len));
- return this;
- }
-
- /**
- * Bind a character stream as a parameter
- *
- * @param n The name of the parameter
- * @param r The value for the parameter
- * @param len The length of the stream
- * @return The prepared statement
- */
- public NamedPreparedStatement setCharacterStream(String n, java.io.Reader r, int len) {
- singles.put(n, (ps, i) -> ps.setCharacterStream(i, r, len));
- return this;
- }
/* ---------- Binding (lists) ---------- */
- /**
- * Bind a list parameter to the statement
- *
- * @param name The name of the list parameter
- * @param values The values for the list parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setList(String name, Collection<?> values) {
- lists.put(name, toBinders(values, Types.OTHER, false));
- return this;
- }
-
- /**
- * Bind a list parameter to the statement
- *
- * @param name The name of the list parameter
- * @param values The values for the list parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setList(String name, Object... values) {
- lists.put(name, toBinders(Arrays.asList(values), Types.OTHER, false));
- return this;
- }
-
- /**
- * Explicit SQL type for all elements (useful if nulls might appear).
- *
- * @param name The name of the list parameter
- * @param sqlType The SQL type for the parameters
- * @param values The values for the list parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setList(String name, int sqlType, Collection<?> values) {
- lists.put(name, toBinders(values, sqlType, true));
- return this;
- }
-
- /**
- * Explicit SQL type for all elements (useful if nulls might appear).
- *
- * @param name The name of the list parameter
- * @param sqlType The SQL type for the parameters
- * @param values The values for the list parameter
- * @return The prepared statement
- */
- public NamedPreparedStatement setList(String name, int sqlType, Object... values) {
- lists.put(name, toBinders(Arrays.asList(values), sqlType, true));
- return this;
- }
+
/* ---------- Build & bind ---------- */
@@ -689,6 +323,10 @@ public final class NamedPreparedStatement implements AutoCloseable {
}
private List<Binder> buildPreparedStatement() throws SQLException {
+ return buildPreparedStatement(this);
+ }
+
+ private List<Binder> buildPreparedStatement(BoundPreparedStatement record) throws SQLException {
StringBuilder sb = new StringBuilder(originalSql.length() + 32);
List<Binder> bindersInOrder = new ArrayList<>(32);
@@ -742,7 +380,7 @@ public final class NamedPreparedStatement implements AutoCloseable {
}
return bindersInOrder;
}
-
+
/* ---------- Parser ---------- */
private interface Token {
@@ -875,65 +513,6 @@ public final class NamedPreparedStatement implements AutoCloseable {
/* ---------- Helpers ---------- */
- @FunctionalInterface
- private interface Binder {
- void bind(PreparedStatement ps, int index) throws SQLException;
- }
-
- private static List<Binder> toBinders(Collection<?> values, int sqlType, boolean forceType) {
- ArrayList<Binder> list = new ArrayList<>(values.size());
- for (Object v : values) {
- final Object val = v;
- if (forceType) {
- list.add((ps, i) -> {
- if (val == null)
- ps.setNull(i, sqlType);
- else
- ps.setObject(i, val, sqlType);
- });
- } else {
- list.add((ps, i) -> ps.setObject(i, val));
- }
- }
- return list;
- }
-
- private static Map<String, List<Binder>> deepCopyLists(Map<String, List<Binder>> src) {
- Map<String, List<Binder>> m = new HashMap<>(src.size());
- for (Map.Entry<String, List<Binder>> e : src.entrySet()) {
- m.put(e.getKey(), new ArrayList<>(e.getValue()));
- }
- return m;
- }
-
- private static class ParamSnapshot {
- public Map<String, Binder> singles;
- public Map<String, List<Binder>> lists;
-
- public ParamSnapshot(Map<String, Binder> singles, Map<String, List<Binder>> lists) {
- super();
- this.singles = singles;
- this.lists = lists;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(lists, singles);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- ParamSnapshot other = (ParamSnapshot) obj;
- return Objects.equals(lists, other.lists) && Objects.equals(singles, other.singles);
- }
- }
-
private enum EmptyListMode {
AS_NULL, AS_CUSTOM_LITERAL
}
diff --git a/base/src/main/java/bjc/utils/misc/ParamSnapshot.java b/base/src/main/java/bjc/utils/misc/ParamSnapshot.java
new file mode 100644
index 0000000..5f2c756
--- /dev/null
+++ b/base/src/main/java/bjc/utils/misc/ParamSnapshot.java
@@ -0,0 +1,33 @@
+package bjc.utils.misc;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+class ParamSnapshot {
+ public Map<String, Binder> singles;
+ public Map<String, List<Binder>> lists;
+
+ public ParamSnapshot(Map<String, Binder> singles, Map<String, List<Binder>> lists) {
+ super();
+ this.singles = singles;
+ this.lists = lists;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(lists, singles);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ParamSnapshot other = (ParamSnapshot) obj;
+ return Objects.equals(lists, other.lists) && Objects.equals(singles, other.singles);
+ }
+} \ No newline at end of file