Fix #9 by combining ->factory and create again

This commit is contained in:
Sean Corfield 2019-04-10 21:46:38 -07:00
parent e5e580846f
commit d2f0afa973
4 changed files with 66 additions and 81 deletions

View file

@ -6,7 +6,7 @@
The basic building blocks are the java.sql/javax.sql classes: The basic building blocks are the java.sql/javax.sql classes:
* DataSource -- something to get connections from, * DataSource -- something to get connections from,
* Connection -- an active connection to the database, * Connection -- an active connection to the database,
* PreparedStatement -- SQL and parameters combined, from a connection * PreparedStatement -- SQL and parameters combined, from a connection,
and the following two functions and a macro: and the following two functions and a macro:
* reducible! -- given a connectable and SQL + parameters or a statement, * reducible! -- given a connectable and SQL + parameters or a statement,
return a reducible that, when reduced will execute the SQL and consume return a reducible that, when reduced will execute the SQL and consume

View file

@ -69,78 +69,63 @@
[return-keys] [return-keys]
(into-array String return-keys)) (into-array String return-keys))
(defn ->factory (defn create
"Given a some options, return a statement factory -- a function that will "Given a connection, a SQL string, some parameters, and some options,
accept a connection and a SQL string and parameters, and return a return a PreparedStatement representing that."
PreparedStatement representing that." ^java.sql.PreparedStatement
[{:keys [return-keys result-type concurrency cursors [^Connection con ^String sql params
{:keys [return-keys result-type concurrency cursors
fetch-size max-rows timeout]}] fetch-size max-rows timeout]}]
(cond-> (let [^PreparedStatement ps
(cond (cond
return-keys return-keys
(do (do
(when (or result-type concurrency cursors) (when (or result-type concurrency cursors)
(throw (IllegalArgumentException. (throw (IllegalArgumentException.
(str ":concurrency, :cursors, and :result-type " (str ":concurrency, :cursors, and :result-type "
"may not be specified with :return-keys.")))) "may not be specified with :return-keys."))))
(if (vector? return-keys) (if (vector? return-keys)
(let [key-names (string-array return-keys)] (let [key-names (string-array return-keys)]
(fn [^Connection con ^String sql]
(try
(try (try
(.prepareStatement con sql key-names) (try
(.prepareStatement con sql key-names)
(catch Exception _
;; assume it is unsupported and try regular generated keys:
(.prepareStatement con sql Statement/RETURN_GENERATED_KEYS)))
(catch Exception _ (catch Exception _
;; assume it is unsupported and try regular generated keys: ;; assume it is unsupported and try basic PreparedStatement:
(.prepareStatement con sql Statement/RETURN_GENERATED_KEYS))) (.prepareStatement con sql))))
(try
(.prepareStatement con sql Statement/RETURN_GENERATED_KEYS)
(catch Exception _ (catch Exception _
;; assume it is unsupported and try basic PreparedStatement: ;; assume it is unsupported and try basic PreparedStatement:
(.prepareStatement con sql))))) (.prepareStatement con sql)))))
(fn [^Connection con ^String sql]
(try
(.prepareStatement con sql Statement/RETURN_GENERATED_KEYS)
(catch Exception _
;; assume it is unsupported and try basic PreparedStatement:
(.prepareStatement con sql))))))
(and result-type concurrency) (and result-type concurrency)
(if cursors (if cursors
(fn [^Connection con ^String sql] (.prepareStatement con sql
(.prepareStatement con sql (get result-set-type result-type result-type)
(get result-set-type result-type result-type) (get result-set-concurrency concurrency concurrency)
(get result-set-concurrency concurrency concurrency) (get result-set-holdability cursors cursors))
(get result-set-holdability cursors cursors))) (.prepareStatement con sql
(fn [^Connection con ^String sql] (get result-set-type result-type result-type)
(.prepareStatement con sql (get result-set-concurrency concurrency concurrency)))
(get result-set-type result-type result-type)
(get result-set-concurrency concurrency concurrency))))
(or result-type concurrency cursors) (or result-type concurrency cursors)
(throw (IllegalArgumentException. (throw (IllegalArgumentException.
(str ":concurrency, :cursors, and :result-type " (str ":concurrency, :cursors, and :result-type "
"may not be specified independently."))) "may not be specified independently.")))
:else :else
(fn [^Connection con ^String sql] (.prepareStatement con sql))]
(.prepareStatement con sql))) (when fetch-size
fetch-size (as-> f (.setFetchSize ps fetch-size))
(fn [^Connection con ^String sql] (when max-rows
(.setFetchSize ^PreparedStatement (f con sql) fetch-size))) (.setMaxRows ps max-rows))
max-rows (as-> f (when timeout
(fn [^Connection con ^String sql] (.setQueryTimeout ps timeout))
(.setMaxRows ^PreparedStatement (f con sql) max-rows))) (set-parameters ps params)))
timeout (as-> f
(fn [^Connection con ^String sql]
(.setQueryTimeout ^PreparedStatement (f con sql) timeout)))))
(defn create
"Given a connection, a SQL statement, its parameters, and a statement factory,
return a PreparedStatement representing that."
^java.sql.PreparedStatement
[con sql params factory]
(set-parameters (factory con sql) params))
(extend-protocol p/Preparable (extend-protocol p/Preparable
java.sql.Connection java.sql.Connection
(prepare [this sql-params opts] (prepare [this sql-params opts]
(let [[sql & params] sql-params (create this (first sql-params) (rest sql-params) opts)))
factory (->factory opts)]
(set-parameters (factory this sql) params))))

View file

@ -161,25 +161,23 @@
(extend-protocol p/Executable (extend-protocol p/Executable
java.sql.Connection java.sql.Connection
(-execute [this sql-params opts] (-execute [this sql-params opts]
(let [factory (prepare/->factory opts)] (reify clojure.lang.IReduceInit
(reify clojure.lang.IReduceInit (reduce [_ f init]
(reduce [_ f init] (with-open [stmt (prepare/create this
(with-open [stmt (prepare/create this (first sql-params)
(first sql-params) (rest sql-params)
(rest sql-params) opts)]
factory)] (reduce-stmt stmt f init opts)))))
(reduce-stmt stmt f init opts))))))
javax.sql.DataSource javax.sql.DataSource
(-execute [this sql-params opts] (-execute [this sql-params opts]
(let [factory (prepare/->factory opts)] (reify clojure.lang.IReduceInit
(reify clojure.lang.IReduceInit (reduce [_ f init]
(reduce [_ f init] (with-open [con (p/get-connection this opts)]
(with-open [con (p/get-connection this opts)] (with-open [stmt (prepare/create con
(with-open [stmt (prepare/create con (first sql-params)
(first sql-params) (rest sql-params)
(rest sql-params) opts)]
factory)] (reduce-stmt stmt f init opts))))))
(reduce-stmt stmt f init opts)))))))
java.sql.PreparedStatement java.sql.PreparedStatement
(-execute [this _ opts] (-execute [this _ opts]
(reify clojure.lang.IReduceInit (reify clojure.lang.IReduceInit

View file

@ -113,6 +113,8 @@
nil nil
(reducible! ps))])) (reducible! ps))]))
(require '[next.jdbc.prepare :as prepare])
;; same as above but setting parameters inside the benchmark ;; same as above but setting parameters inside the benchmark
(with-open [ps (prepare con ["select * from fruit where appearance = ?"] {})] (with-open [ps (prepare con ["select * from fruit where appearance = ?"] {})]
(quick-bench (quick-bench