From d2f0afa97349dd4fffdcbe52bbb347184b7c3164 Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Wed, 10 Apr 2019 21:46:38 -0700 Subject: [PATCH] Fix #9 by combining ->factory and create again --- src/next/jdbc.clj | 2 +- src/next/jdbc/prepare.clj | 111 +++++++++++++++-------------------- src/next/jdbc/result_set.clj | 32 +++++----- test/next/jdbc_test.clj | 2 + 4 files changed, 66 insertions(+), 81 deletions(-) diff --git a/src/next/jdbc.clj b/src/next/jdbc.clj index f9d1f0b..3e10b5d 100644 --- a/src/next/jdbc.clj +++ b/src/next/jdbc.clj @@ -6,7 +6,7 @@ The basic building blocks are the java.sql/javax.sql classes: * DataSource -- something to get connections from, * 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: * reducible! -- given a connectable and SQL + parameters or a statement, return a reducible that, when reduced will execute the SQL and consume diff --git a/src/next/jdbc/prepare.clj b/src/next/jdbc/prepare.clj index f476da3..1327415 100644 --- a/src/next/jdbc/prepare.clj +++ b/src/next/jdbc/prepare.clj @@ -69,78 +69,63 @@ [return-keys] (into-array String return-keys)) -(defn ->factory - "Given a some options, return a statement factory -- a function that will - accept a connection and a SQL string and parameters, and return a - PreparedStatement representing that." - [{:keys [return-keys result-type concurrency cursors +(defn create + "Given a connection, a SQL string, some parameters, and some options, + return a PreparedStatement representing that." + ^java.sql.PreparedStatement + [^Connection con ^String sql params + {:keys [return-keys result-type concurrency cursors fetch-size max-rows timeout]}] - (cond-> - (cond - return-keys - (do - (when (or result-type concurrency cursors) - (throw (IllegalArgumentException. - (str ":concurrency, :cursors, and :result-type " - "may not be specified with :return-keys.")))) - (if (vector? return-keys) - (let [key-names (string-array return-keys)] - (fn [^Connection con ^String sql] - (try + (let [^PreparedStatement ps + (cond + return-keys + (do + (when (or result-type concurrency cursors) + (throw (IllegalArgumentException. + (str ":concurrency, :cursors, and :result-type " + "may not be specified with :return-keys.")))) + (if (vector? return-keys) + (let [key-names (string-array return-keys)] (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 _ - ;; assume it is unsupported and try regular generated keys: - (.prepareStatement con sql Statement/RETURN_GENERATED_KEYS))) + ;; assume it is unsupported and try basic PreparedStatement: + (.prepareStatement con sql)))) + (try + (.prepareStatement con sql Statement/RETURN_GENERATED_KEYS) (catch Exception _ ;; assume it is unsupported and try basic PreparedStatement: (.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) - (if cursors - (fn [^Connection con ^String sql] - (.prepareStatement con sql - (get result-set-type result-type result-type) - (get result-set-concurrency concurrency concurrency) - (get result-set-holdability cursors cursors))) - (fn [^Connection con ^String sql] - (.prepareStatement con sql - (get result-set-type result-type result-type) - (get result-set-concurrency concurrency concurrency)))) + (and result-type concurrency) + (if cursors + (.prepareStatement con sql + (get result-set-type result-type result-type) + (get result-set-concurrency concurrency concurrency) + (get result-set-holdability cursors cursors)) + (.prepareStatement con sql + (get result-set-type result-type result-type) + (get result-set-concurrency concurrency concurrency))) - (or result-type concurrency cursors) - (throw (IllegalArgumentException. - (str ":concurrency, :cursors, and :result-type " - "may not be specified independently."))) - :else - (fn [^Connection con ^String sql] - (.prepareStatement con sql))) - fetch-size (as-> f - (fn [^Connection con ^String sql] - (.setFetchSize ^PreparedStatement (f con sql) fetch-size))) - max-rows (as-> f - (fn [^Connection con ^String sql] - (.setMaxRows ^PreparedStatement (f con sql) max-rows))) - 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)) + (or result-type concurrency cursors) + (throw (IllegalArgumentException. + (str ":concurrency, :cursors, and :result-type " + "may not be specified independently."))) + :else + (.prepareStatement con sql))] + (when fetch-size + (.setFetchSize ps fetch-size)) + (when max-rows + (.setMaxRows ps max-rows)) + (when timeout + (.setQueryTimeout ps timeout)) + (set-parameters ps params))) (extend-protocol p/Preparable java.sql.Connection (prepare [this sql-params opts] - (let [[sql & params] sql-params - factory (->factory opts)] - (set-parameters (factory this sql) params)))) + (create this (first sql-params) (rest sql-params) opts))) diff --git a/src/next/jdbc/result_set.clj b/src/next/jdbc/result_set.clj index 2677d16..49f2e8f 100644 --- a/src/next/jdbc/result_set.clj +++ b/src/next/jdbc/result_set.clj @@ -161,25 +161,23 @@ (extend-protocol p/Executable java.sql.Connection (-execute [this sql-params opts] - (let [factory (prepare/->factory opts)] - (reify clojure.lang.IReduceInit - (reduce [_ f init] - (with-open [stmt (prepare/create this - (first sql-params) - (rest sql-params) - factory)] - (reduce-stmt stmt f init opts)))))) + (reify clojure.lang.IReduceInit + (reduce [_ f init] + (with-open [stmt (prepare/create this + (first sql-params) + (rest sql-params) + opts)] + (reduce-stmt stmt f init opts))))) javax.sql.DataSource (-execute [this sql-params opts] - (let [factory (prepare/->factory opts)] - (reify clojure.lang.IReduceInit - (reduce [_ f init] - (with-open [con (p/get-connection this opts)] - (with-open [stmt (prepare/create con - (first sql-params) - (rest sql-params) - factory)] - (reduce-stmt stmt f init opts))))))) + (reify clojure.lang.IReduceInit + (reduce [_ f init] + (with-open [con (p/get-connection this opts)] + (with-open [stmt (prepare/create con + (first sql-params) + (rest sql-params) + opts)] + (reduce-stmt stmt f init opts)))))) java.sql.PreparedStatement (-execute [this _ opts] (reify clojure.lang.IReduceInit diff --git a/test/next/jdbc_test.clj b/test/next/jdbc_test.clj index d356db9..8f8d20d 100644 --- a/test/next/jdbc_test.clj +++ b/test/next/jdbc_test.clj @@ -113,6 +113,8 @@ nil (reducible! ps))])) + (require '[next.jdbc.prepare :as prepare]) + ;; same as above but setting parameters inside the benchmark (with-open [ps (prepare con ["select * from fruit where appearance = ?"] {})] (quick-bench