Skip to content

Commit 353235e

Browse files
committed
Change how parameters are passed to execute; few other cleanups
1 parent 09bd091 commit 353235e

1 file changed

Lines changed: 39 additions & 27 deletions

File tree

src/DBInterface.jl

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ macro prepare(getDB, sql)
5353
key = gensym()
5454
return quote
5555
get!(DBInterface.PREPARED_STMTS, $(QuoteNode(key))) do
56-
println("preparing stmt")
5756
DBInterface.prepare($(esc(getDB)), $sql)
5857
end
5958
end
@@ -63,54 +62,67 @@ end
6362
abstract type Cursor end
6463

6564
"""
66-
DBInterface.execute!(conn::DBInterface.Connection, sql::AbstractString, args...; kw...) => DBInterface.Cursor
67-
DBInterface.execute!(stmt::DBInterface.Statement, args...; kw...) => DBInterface.Cursor
65+
DBInterface.execute!(conn::DBInterface.Connection, sql::AbstractString, [params]) => DBInterface.Cursor
66+
DBInterface.execute!(stmt::DBInterface.Statement, [params]) => DBInterface.Cursor
6867
6968
Database packages should overload `DBInterface.execute!` for a valid, prepared `DBInterface.Statement` subtype (the first method
70-
signature is defined in DBInterface.jl using `DBInterface.prepare`), which takes zero or more `args` or `kw` arguments that should
71-
be bound against the `stmt` (`args` as positional parameters, `kw` as named parameters, but not mixed) before executing the query
72-
against the database. `DBInterface.execute!` should return a valid `DBInterface.Cursor` object, which is any iterator of "rows",
69+
signature is defined in DBInterface.jl using `DBInterface.prepare`), which takes an optional `params` argument, which should be
70+
an indexable collection (`Vector` or `Tuple`) for positional parameters, or a `NamedTuple` for named parameters.
71+
`DBInterface.execute!` should return a valid `DBInterface.Cursor` object, which is any iterator of "rows",
7372
which themselves must be property-accessible (i.e. implement `propertynames` and `getproperty` for value access by name),
7473
and indexable (i.e. implement `length` and `getindex` for value access by index). These "result" objects do not need
7574
to subtype `DBInterface.Cursor` explicitly as long as they satisfy the interface. For DDL/DML SQL statements, which typically
7675
do not return results, an iterator is still expected to be returned that just iterates `nothing`, i.e. an "empty" iterator.
7776
"""
7877
function execute! end
7978

80-
execute!(stmt::Statement, args...; kw...) = throw(NotImplementedError("`DBInterface.execute!` not implemented for `$(typeof(stmt))`"))
79+
execute!(stmt::Statement, params=()) = throw(NotImplementedError("`DBInterface.execute!` not implemented for `$(typeof(stmt))`"))
8180

82-
execute!(conn::Connection, sql::AbstractString, args...; kw...) = execute!(prepare(conn, sql), args...; kw...)
81+
execute!(conn::Connection, sql::AbstractString, params=()) = execute!(prepare(conn, sql), params)
82+
83+
struct LazyIndex{T} <: AbstractVector{Any}
84+
x::T
85+
i::Int
86+
end
87+
88+
Base.IndexStyle(::Type{<:LazyIndex}) = Base.IndexLinear()
89+
Base.IteratorSize(::Type{<:LazyIndex}) = Base.HasLength()
90+
Base.size(x::LazyIndex) = (length(x.x),)
91+
Base.getindex(x::LazyIndex, i::Int) = x.x[i][x.i]
8392

8493
"""
85-
DBInterface.executemany!(conn::DBInterface.Connect, sql::AbstractString, args...; kw...) => Nothing
86-
DBInterface.executemany!(stmt::DBInterface.Statement, args...; kw...) => Nothing
94+
DBInterface.executemany!(conn::DBInterface.Connect, sql::AbstractString, [params]) => Nothing
95+
DBInterface.executemany!(stmt::DBInterface.Statement, [params]) => Nothing
8796
88-
Similar to
97+
Similar in usage to `DBInterface.execute!`, but allows passing multiple sets of parameters to be executed in sequence.
98+
`params`, like for `DBInterface.execute!`, should be an indexable collection (`Vector` or `Tuple`) or `NamedTuple`, but instead
99+
of a single scalar value per parameter, an indexable collection should be passed for each parameter. By default, each set of
100+
parameters will be looped over and `DBInterface.execute!` will be called for each. Note that no result sets or cursors are returned
101+
for any execution, so the usage is mainly intended for bulk INSERT statements.
89102
"""
90-
function executemany!(stmt::Statement, args...; kw...)
91-
if !isempty(args)
92-
arg = args[1]
93-
len = length(arg)
94-
all(x -> length(x) == len, args) || throw(ParameterError("positional parameters provided to `DBInterface.executemany!` do not all have the same number of parameters"))
95-
for i = 1:len
96-
xargs = map(x -> x[i], args)
97-
execute!(stmt, xargs...)
98-
end
99-
elseif !isempty(kw)
100-
k = kw[1]
101-
len = length(k)
102-
all(x -> length(x) == len, kw) || throw(ParameterError("named parameters provided to `DBInterface.executemany!` do not all have the same number of parameters"))
103+
function executemany!(stmt::Statement, params=())
104+
if !isempty(params)
105+
param = params[1]
106+
len = length(param)
107+
all(x -> length(x) == len, params) || throw(ParameterError("parameters provided to `DBInterface.executemany!` do not all have the same number of parameters"))
103108
for i = 1:len
104-
xargs = collect(k=>v[i] for (k, v) in kw)
105-
execute!(stmt; xargs...)
109+
xargs = LazyIndex(params, i)
110+
execute!(stmt, xargs)
106111
end
107112
else
108113
execute!(stmt)
109114
end
110115
return
111116
end
112117

113-
executemany!(conn::Connection, sql::AbstractString, args...; kw...) = executemany!(prepare(conn, sql), args...; kw...)
118+
executemany!(conn::Connection, sql::AbstractString, params=()) = executemany!(prepare(conn, sql), params)
119+
120+
"""
121+
DBInterface.close!(stmt::DBInterface.Statement)
122+
123+
Close a prepared statement so further queries cannot be executed.
124+
"""
125+
function close! end
114126

115127
"""
116128
DBInterface.lastrowid(x::Cursor) => Int

0 commit comments

Comments
 (0)