Skip to content

Commit

Permalink
Add getconnection/transaction
Browse files Browse the repository at this point in the history
In `DBInterface.executemany`, it's much more efficient for databases to
wrap multiple `execute` invocations in transactions, so we add
`transaction` for individual database packages to overload and we need
`getconnection` in order to get the `Connection` for a `Statement`.
  • Loading branch information
quinnj committed Oct 23, 2021
1 parent 91e208a commit 7712414
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 3 deletions.
2 changes: 2 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ across various database packages.
## Functions
```@docs
DBInterface.connect
DBInterface.getconnection
DBInterface.prepare
DBInterface.@prepare
DBInterface.execute
DBInterface.transaction
DBInterface.executemany
DBInterface.executemultiple
DBInterface.close!
Expand Down
28 changes: 25 additions & 3 deletions src/DBInterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ close!(conn::Connection)
"Database packages should provide a `DBInterface.Statement` subtype which represents a valid, prepared SQL statement that can be executed repeatedly"
abstract type Statement end

"""
DBInterface.getconnection(::DBInterface.Statement)
For a valid `DBInterface.Statement`, return the `DBInterface.Connection` the statement
is associated with.
"""
function getconnection end

"""
DBInterface.prepare(conn::DBInterface.Connection, sql::AbstractString) => DBInterface.Statement
DBInterface.prepare(f::Function, sql::AbstractString) => DBInterface.Statement
Expand Down Expand Up @@ -145,6 +153,18 @@ execute(conn::Connection, sql::AbstractString; kwargs...) = execute(conn, sql, v
execute(f::Base.Callable, conn::Connection, sql::AbstractString; kwargs...) = execute(f, conn, sql, values(kwargs))
execute(f::Base.Callable, stmt::Statement; kwargs...) = execute(f, stmt, values(kwargs))

"""
DBInterface.transaction(f, conn::DBInterface.Connection)
Open a transaction against a database connection `conn`, execute a closure `f`,
then "commit" the transaction after executing the closure function. The default
definition in DBInterface.jl is a no-op in that it just executes the closure
function with no transaction. Used in `DBInterface.executemany` to wrap the
individual execute calls in a transaction since this often leads to much better
performance in database systems.
"""
transaction(f, ::Connection) = f()

struct LazyIndex{T} <: AbstractVector{Any}
x::T
i::Int
Expand All @@ -170,9 +190,11 @@ function executemany(stmt::Statement, params)
param = params[1]
len = length(param)
all(x -> length(x) == len, params) || throw(ParameterError("parameters provided to `DBInterface.executemany!` do not all have the same number of parameters"))
for i = 1:len
xargs = LazyIndex(params, i)
execute(stmt, xargs)
transaction(getconnection(stmt)) do
for i = 1:len
xargs = LazyIndex(params, i)
execute(stmt, xargs)
end
end
else
execute(stmt)
Expand Down

0 comments on commit 7712414

Please sign in to comment.