Skip to content

Commit 4988224

Browse files
authored
Merge pull request #22 from JuliaDatabases/jq/updates
Few updates
2 parents 09bd091 + b3cd750 commit 4988224

3 files changed

Lines changed: 52 additions & 38 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DBInterface"
22
uuid = "a10d1c49-ce27-4219-8d33-6db1a4562965"
33
authors = ["Jacob Quinn <quinn.jacobd@gmail.com>"]
4-
version = "1.0.1"
4+
version = "2.0.0"
55

66
[compat]
77
julia = "1"

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ conn = DBInterface.connect(T, args...; kw...) # create a connection to a specifi
1111

1212
stmt = DBInterface.prepare(conn, sql) # prepare a sql statement against the connection; returns a statement object
1313

14-
results = DBInterface.execute!(stmt) # execute a prepared statement; returns an iterator of rows (property-accessible & indexable)
14+
results = DBInterface.execute(stmt) # execute a prepared statement; returns an iterator of rows (property-accessible & indexable)
1515

1616
rowid = DBInterface.lastrowid(results) # get the last row id of an INSERT statement, as supported by the database
1717

@@ -26,17 +26,19 @@ end
2626
df = DataFrame(results)
2727
CSV.write("results.csv", results)
2828

29-
results = DBInterface.execute!(conn, sql) # convenience method if statement preparation/re-use isn't needed
29+
results = DBInterface.execute(conn, sql) # convenience method if statement preparation/re-use isn't needed
3030

3131
stmt = DBInterface.prepare(conn, "INSERT INTO test_table VALUES(?, ?)") # prepare a statement with positional parameters
3232

33-
DBInterface.execute!(stmt, 1, 3.14) # execute the prepared INSERT statement, passing 1 and 3.14 as positional parameters
33+
DBInterface.execute(stmt, [1, 3.14]) # execute the prepared INSERT statement, passing 1 and 3.14 as positional parameters
3434

3535
stmt = DBInterface.prepare(conn, "INSERT INTO test_table VALUES(:col1, :col2)") # prepare a statement with named parameters
3636

37-
DBInterface.execute!(stmt; col1=1, col2=3.14) # execute the prepared INSERT statement, with 1 and 3.14 as named parameters
37+
DBInterface.execute(stmt, (col1=1, col2=3.14)) # execute the prepared INSERT statement, with 1 and 3.14 as named parameters
3838

39-
DBInterface.executemany!(stmt; col1=[1,2,3,4,5], col2=[3.14, 1.23, 2.34 3.45, 4.56]) # execute the prepared statement multiple times for each set of named parameters; each named parameter must be an indexable collection
39+
DBInterface.executemany(stmt, (col1=[1,2,3,4,5], col2=[3.14, 1.23, 2.34 3.45, 4.56])) # execute the prepared statement multiple times for each set of named parameters; each named parameter must be an indexable collection
40+
41+
DBInterface.close!(stmt) # close the prepared statement
4042
```
4143

4244
### For Database Package Developers
@@ -47,6 +49,6 @@ DBInterface.connect
4749
DBInterface.close!
4850
DBInterface.Statement
4951
DBInterface.prepare
50-
DBInterface.execute!
52+
DBInterface.execute
5153
DBInterface.lastrowid
5254
```

src/DBInterface.jl

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,64 +53,76 @@ 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
6059
end
6160

62-
"Any object that iterates \"rows\", which are objects that are property-accessible and indexable. See `DBInterface.execute!` for more details on fetching query results."
61+
"Any object that iterates \"rows\", which are objects that are property-accessible and indexable. See `DBInterface.execute` for more details on fetching query results."
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
69-
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",
68+
Database packages should overload `DBInterface.execute` for a valid, prepared `DBInterface.Statement` subtype (the first method
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
"""
78-
function execute! end
77+
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
108-
execute!(stmt)
113+
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+
close!(stmt::Statement) = throw(NotImplementedError("`DBInterface.close!` not implemented for `$(typeof(stmt))`"))
114126

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

0 commit comments

Comments
 (0)