Skip to content
This repository was archived by the owner on Apr 17, 2021. It is now read-only.

Commit 448348a

Browse files
Merge pull request #26 from shopsmart/db_cursor_batching_002
Add function for processing query resultsets as a cursor (in batches)…
2 parents dedfddc + af80652 commit 448348a

File tree

2 files changed

+73
-4
lines changed

2 files changed

+73
-4
lines changed

project.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
(defproject com.github.shopsmart/clj-infrastructure "0.1.19"
1+
(defproject com.github.shopsmart/clj-infrastructure "0.1.20"
22
:description "Infrastructure helpers for AWS, database, etc."
33
:url "https://github.com/shopsmart/clj-infrastructure"
44

src/clj_infrastructure/db.clj

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@
2929
(:import [java.sql PreparedStatement SQLException])
3030
(:gen-class))
3131

32-
(def DB_EXEC_MODE_QUERY "query")
33-
(def DB_EXEC_MODE_EXEC "execute")
32+
(def DB_EXEC_MODE_QUERY "query")
33+
(def DB_EXEC_MODE_QUERY_CURSOR "query_cursor")
34+
(def DB_EXEC_MODE_EXEC "execute")
3435

3536
;; Error handling ----------------------------------------------------------------------------
3637

@@ -669,6 +670,61 @@
669670
detail-map))
670671

671672

673+
(defn sql-cursor->result-set-fn-results [
674+
conn
675+
[sql & params :as sql-params]
676+
result-set-fn &
677+
[{:keys [transaction? as-arrays? fetch-size] :as opt-map}]]
678+
679+
"""
680+
Runs the provided SQL and passes the result set cursor to the provided
681+
result set function. Using a cursor allows rows to be fetched in batches
682+
(of size (:fetch-size opt-map)), but requires the a function to process
683+
results due to the need to manage the transaction and cursor requirements
684+
properly (i.e. ensure auto commit is off, that the cursor is closed, etc.)
685+
686+
The interface works with parameters as expected by other clojure.java.jdbc
687+
function.
688+
689+
TODO: Add handling of :multi? opt key
690+
"""
691+
692+
; Factored out body of function:
693+
(let [
694+
body-fn
695+
(fn fn-body-sql->cursor [
696+
conn
697+
[sql & params :as sql-params] &
698+
[{:keys [transaction? as-arrays? fetch-size] :as opt-map}]]
699+
700+
(let [fetch-size (or fetch-size 1000)]
701+
702+
(with-open [
703+
cursor
704+
(let [stmt (.prepareStatement (:connection conn) sql)]
705+
(doseq [[index value] (map vector (iterate inc 1) params)]
706+
(.setObject stmt index value))
707+
(.setFetchSize stmt fetch-size)
708+
(.executeQuery stmt))]
709+
710+
(result-set-fn
711+
(if (true? as-arrays?)
712+
(do (map #(into [] (vals %)) (resultset-seq cursor)))
713+
(do (resultset-seq cursor)))))))]
714+
715+
; Run the body optionally wrapped in a transaction
716+
(let [auto-commit-val (.getAutoCommit (:connection conn))]
717+
(if (or transaction? auto-commit-val)
718+
(do
719+
(.setAutoCommit (:connection conn) false)
720+
(clojure.java.jdbc/with-db-transaction [conn (dbconfig {} "connection")]
721+
(body-fn conn sql-params opt-map))
722+
(when (true? auto-commit-val)
723+
(.commit (:connection conn))
724+
(.setAutoCommit (:connection conn) auto-commit-val)))
725+
(do (body-fn conn sql-params opt-map))))))
726+
727+
672728
(defn run-statement
673729
[conn {:keys [stmt-text exec-mode op-comment binds opt-map commit?] :as stmt-detail-map}]
674730

@@ -686,7 +742,19 @@
686742
(let [updated-map
687743
(assoc-in stmt-detail-map [:result]
688744
(cond
689-
(= exec-mode DB_EXEC_MODE_QUERY)
745+
(and (:result-set-fn opt-map) (= exec-mode DB_EXEC_MODE_QUERY_CURSOR))
746+
; Execute query using cursor to fetch results in batches (requires a
747+
; result set function that processes rows)
748+
(do
749+
(log/debug
750+
"Issuing statement as query with cursor and batch "
751+
"fetching (results expected) ...")
752+
(sql-cursor->result-set-fn-results conn sql-params (:result-set-fn opt-map) opt-map))
753+
(or
754+
(= exec-mode DB_EXEC_MODE_QUERY)
755+
(and (= exec-mode DB_EXEC_MODE_QUERY_CURSOR) (not (:result-set-fn opt-map))))
756+
; Execute a query using clojure query function; all results
757+
; are materialized during the fetch
690758
(do
691759
(log/debug "Issuing statement as query (results expected) ...")
692760
(clojure.java.jdbc/query conn sql-params opt-map))
@@ -729,3 +797,4 @@
729797
(for [stmt-detail-map stmt-detail-vec]
730798
(run-statement conn stmt-detail-map))))))
731799

800+

0 commit comments

Comments
 (0)