diff --git a/doc/prepared_stmt.md b/doc/prepared_stmt.md index 8fd9364..2a6e3cb 100644 --- a/doc/prepared_stmt.md +++ b/doc/prepared_stmt.md @@ -1,3 +1,29 @@ # Prepared Statements +Under the hood, whenever you ask `next.jdbc` to execute some SQL it creates a `java.sql.PreparedStatement`, adds in the parameters you provide, and then calls `.execute` on it. Then it attempts to get a `ResultSet` from that and either return it or process it. If you asked for generated keys to be returned, that `ResultSet` will contain the those generated keys if your database supports it, otherwise it will be whatever the `.execute` function produces. If no `ResultSet` is available at all, `next.jdbc` will ask for the count of updated rows and return that as if it were a result set. + +If you have a SQL operation that you intend to run multiple times on the same `java.sql.Connection`, it may be worth creating the prepared statement yourself and reusing it. `next.jdbc/prepare` accepts a connection and a vector of SQL and optional parameters and returns a `java.sql.PreparedStatement` which can be passed to `reducible!`, `execute!`, or `execute-one!` as the first argument. It is your responsibility to close the prepared statement after it has been used. + +If you need to pass an option map to `reducible!`, `execute!`, or `execute-one!` when passing a prepared statement, you must pass `nil` or `[]` as the second argument: + +```clojure +(with-open [con (jdbc/get-connection ds)] + (with-open [ps (jdbc/prepare con ["..." ...])] + (execute-one! ps nil {...}))) +``` + +## Prepared Statement Parameters + +If parameters are provided in the vector along with the SQL statement, in the call to `prepare`, then `set-parameter` is called for each of them. This is part of the `SettableParameter` protocol: + +* `(set-parameter v ps i)` -- by default this calls `(.setObject ps i v)` (for `nil` and `Object`) + +This can be extended to any Clojure data type, to provide a customized way to add specific types of values as parameters to any `PreparedStatement`. + +`next.jdbc/set-parameters` is available for you to call on any existing `PreparedStatement` to set or update the parameters that will be used when the statement is executed: + +* `(set-parameters ps params)` -- loops over a sequence of parameter values and calls `set-parameter` for each one, as above. + +If you need more specialized parameter handling than the protocol can provide, then you can create prepared statements explicitly, instead of letting `next.jdbc` do it for you, and then calling your own variant of `set-parameters` to install those parameters. + [[Prev: Row and Result Set Builders|rs_builders]] [[Next: Transactions|transactions]] diff --git a/doc/rs_builders.md b/doc/rs_builders.md index dcebc49..e0054e7 100644 --- a/doc/rs_builders.md +++ b/doc/rs_builders.md @@ -24,7 +24,7 @@ This protocol defines four functions and is used whenever `next.jdbc` needs to m * `(with-column builder row i)` -- given the row so far, fetches column `i` from the current row of the `ResultSet`, converts it to a Clojure value, and adds it to the row (for `as-maps` this is a call to `.getObject`, a call to `read-column-by-index` -- see the `ReadableColumn` protocol below, and a call to `assoc!`), * `(row! builder row)` -- completes the row (a `(persistent! row)` call by default). -## ResulSet Protocol +## ResultSet Protocol This protocol defines three functions and is used whenever `next.jdbc` needs to materialize a result set (multiple rows) from a `ResultSet` as a Clojure data structure: @@ -48,6 +48,6 @@ The default implementation of this protocol is for these two functions to return Common extensions here could include converting `java.sql.Timestamp` to `java.time.Instant` for example but `next.jdbc` makes no assumptions beyond `nil` and `Boolean`. -Note that the converse, converting Clojure values to database-specific types is handled by the `SettableParameters`, discussed in the section on [[prepared statements|prepared_stmt]] +Note that the converse, converting Clojure values to database-specific types is handled by the `SettableParameters`, discussed in the section on [[prepared statements|prepared_stmt#prepared-statement-parameters]] [[Prev: Friendly SQL Functions|friendly_sql_fns]] [[Next: Prepared Statements|prepared_stmt]] diff --git a/src/next/jdbc/result_set.clj b/src/next/jdbc/result_set.clj index c82a0a5..5dadb13 100644 --- a/src/next/jdbc/result_set.clj +++ b/src/next/jdbc/result_set.clj @@ -400,7 +400,7 @@ (datafiable-row (row-builder (as-maps rs opts)) (.getConnection this) opts)) {:next.jdbc/update-count (.getUpdateCount this)})) - (-execute-all [this sql-params opts] + (-execute-all [this _ opts] (if-let [rs (stmt->result-set this opts)] (let [gen-fn (get opts :gen-fn as-maps) gen (gen-fn rs opts)]