Skip to content

Commit 147d3b5

Browse files
committed
Cleanups for 1.0 release
1 parent b69f361 commit 147d3b5

File tree

6 files changed

+67
-62
lines changed

6 files changed

+67
-62
lines changed

Project.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
1616
[compat]
1717
julia = "1"
1818
BinaryProvider = "0.5"
19-
DBInterface = "1"
20-
Tables = "0.2"
19+
DBInterface = "2"
20+
Tables = "1"
2121
DecFP = "0.4"
2222
MariaDB_Connector_C_jll = "3"
2323
Parsers = "0.3"

README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,11 @@ Escape an SQL statement
125125

126126
Deprecated - see [MySQL.Query](#mysqlquery)
127127

128-
#### MySQL.execute!
128+
#### MySQL.execute
129129

130130
```julia
131-
MySQL.execute!(conn::MySQL.Connection, sql::String)
132-
MySQL.execute!(stmt::MySQL.Stmt, params)
131+
MySQL.execute(conn::MySQL.Connection, sql::String)
132+
MySQL.execute(stmt::MySQL.Stmt, params)
133133
```
134134
Execute an SQL statement without returning results (useful for DDL statements, update, delete, etc.)
135135

@@ -158,13 +158,13 @@ MySQL.Stmt(conn::MySQL.Connection, sql::String) => MySQL.Stmt
158158
```
159159
A prepared SQL statement that may contain `?` parameter placeholders.
160160

161-
A `MySQL.Stmt` may then be executed by calling `MySQL.execute!(stmt, params)` where
161+
A `MySQL.Stmt` may then be executed by calling `MySQL.execute(stmt, params)` where
162162
`params` is a vector with the values to be bound to the `?` placeholders in the
163163
original SQL statement. Params must be provided for every `?` and will be matched in the same order they
164164
appeared in the original SQL statement.
165165

166166
Alternately, a source implementing the Tables.jl interface can be streamed by executing
167-
`MySQL.execute!(itr, stmt)`. Each row must have a value for each param.
167+
`MySQL.execute(itr, stmt)`. Each row must have a value for each param.
168168

169169
#### MySQL.Query
170170

@@ -196,7 +196,7 @@ num_foo = foo[1,1]
196196
my_stmt = MySQL.Stmt(conn, """INSERT INTO my_second_table ('foo_id','foo_name') VALUES (?,?);""")
197197

198198
for i = 1:num_foo
199-
MySQL.execute!(my_stmt, [i, "foo_$i"])
199+
MySQL.execute(my_stmt, [i, "foo_$i"])
200200
end
201201

202202
MySQL.disconnect(conn)

docs/src/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
DBInterface.connect
99
DBInterface.close!
1010
MySQL.escape
11-
DBInterface.execute!
11+
DBInterface.execute
1212
DBInterface.prepare
1313
DBInterface.lastrowid
1414
```

src/execute.jl

+17-13
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ mutable struct TextCursor{buffered} <: DBInterface.Cursor
1010
lookup::Dict{Symbol, Int}
1111
end
1212

13-
struct TextRow{buffered} <: AbstractVector{Any}
13+
struct TextRow{buffered} <: Tables.AbstractRow
1414
cursor::TextCursor{buffered}
1515
row::Ptr{Ptr{UInt8}}
1616
lengths::Vector{Culong}
@@ -20,9 +20,7 @@ getcursor(r::TextRow) = getfield(r, :cursor)
2020
getrow(r::TextRow) = getfield(r, :row)
2121
getlengths(r::TextRow) = getfield(r, :lengths)
2222

23-
Base.size(r::TextRow) = (getcursor(r).nfields,)
24-
Base.IndexStyle(::Type{<:TextRow}) = Base.IndexLinear()
25-
Base.propertynames(r::TextRow) = getcursor(r).names
23+
Tables.columnnames(r::TextRow) = getcursor(r).names
2624

2725
cast(::Type{Union{Missing, T}}, ptr, len) where {T} = ptr == C_NULL ? missing : cast(T, ptr, len)
2826

@@ -67,16 +65,14 @@ function cast(::Type{DateTime}, ptr, len)
6765
casterror(DateTime, ptr, len)
6866
end
6967

70-
function Base.getindex(r::TextRow, i::Int)
71-
return cast(getcursor(r).types[i], unsafe_load(getrow(r), i), getlengths(r)[i])
68+
function Tables.getcolumn(r::TextRow, ::Type{T}, i::Int, nm::Symbol) where {T}
69+
return cast(T, unsafe_load(getrow(r), i), getlengths(r)[i])
7270
end
7371

74-
Base.getindex(r::TextRow, nm::Symbol) = getindex(r, getcursor(r).lookup[nm])
75-
Base.getproperty(r::TextRow, nm::Symbol) = getindex(r, getcursor(r).lookup[nm])
72+
Tables.getcolumn(r::TextRow, i::Int) = Tables.getcolumn(r, getcursor(r).types[i], i, getcursor(r).names[i])
73+
Tables.getcolumn(r::TextRow, nm::Symbol) = Tables.getcolumn(r, getcursor(r).lookup[nm])
7674

77-
Tables.istable(::Type{<:TextCursor}) = true
78-
Tables.rowaccess(::Type{<:TextCursor}) = true
79-
Tables.rows(q::TextCursor) = q
75+
Tables.isrowtable(::Type{<:TextCursor}) = true
8076
Tables.schema(c::TextCursor) = Tables.Schema(c.names, c.types)
8177

8278
Base.eltype(c::TextCursor) = TextRow
@@ -107,7 +103,14 @@ function DBInterface.lastrowid(c::TextCursor)
107103
end
108104

109105
"""
110-
DBInterface.execute!(conn::MySQL.Connection, sql) => MySQL.TextCursor
106+
DBInterface.close!(cursor)
107+
108+
Close a cursor. No more results will be available.
109+
"""
110+
DBInterface.close!(c::TextCursor) = clear!(c.conn)
111+
112+
"""
113+
DBInterface.execute(conn::MySQL.Connection, sql) => MySQL.TextCursor
111114
112115
Execute the SQL `sql` statement with the database connection `conn`. Parameter binding is
113116
only supported via prepared statements, see `?DBInterface.prepare(conn, sql)`.
@@ -117,8 +120,9 @@ Specifying `mysql_store_result=false` will avoid buffering the full resultset to
117120
the query, which has memory use advantages, though ties up the database server since resultset rows must be
118121
fetched one at a time.
119122
"""
120-
function DBInterface.execute!(conn::Connection, sql::AbstractString, args...; mysql_store_result::Bool=true, kw...)
123+
function DBInterface.execute(conn::Connection, sql::AbstractString, params=(); mysql_store_result::Bool=true)
121124
checkconn(conn)
125+
params != () && error("`DBInterface.execute(conn, sql)` does not support parameter binding; see `?DBInterface.prepare(conn, sql)`")
122126
clear!(conn)
123127
API.query(conn.mysql, sql)
124128

src/prepare.jl

+21-20
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ DBInterface.close!(stmt::Statement) = finalize(stmt.stmt)
3333
DBInterface.prepare(conn::MySQL.Connection, sql) => MySQL.Statement
3434
3535
Send a `sql` SQL string to the database to be prepared, returning a `MySQL.Statement` object
36-
that can be passed to `DBInterface.execute!(stmt, args...)` to be repeatedly executed,
36+
that can be passed to `DBInterface.execute(stmt, args...)` to be repeatedly executed,
3737
optionally passing `args` for parameters to be bound on each execution.
3838
3939
Note that `DBInterface.close!(stmt)` should be called once statement executions are finished. Apart from
@@ -80,27 +80,23 @@ struct Cursor{buffered} <: DBInterface.Cursor
8080
rows::Int
8181
end
8282

83-
struct Row <: AbstractVector{Any}
83+
struct Row <: Tables.AbstractRow
8484
cursor::Cursor
8585
end
8686

8787
getcursor(r::Row) = getfield(r, :cursor)
8888

89-
Base.size(r::Row) = (getcursor(r).nfields,)
90-
Base.IndexStyle(::Type{<:Row}) = Base.IndexLinear()
91-
Base.propertynames(r::Row) = getcursor(r).names
89+
Tables.columnnames(r::Row) = getcursor(r).names
9290

93-
function Base.getindex(r::Row, i::Int)
91+
function Tables.getcolumn(r::Row, ::Type{T}, i::Int, nm::Symbol) where {T}
9492
cursor = getcursor(r)
95-
return getvalue(cursor.stmt, cursor.valuehelpers[i], cursor.values, i, cursor.types[i])
93+
return getvalue(cursor.stmt, cursor.valuehelpers[i], cursor.values, i, T)
9694
end
9795

98-
Base.getindex(r::Row, nm::Symbol) = getindex(r, getcursor(r).lookup[nm])
99-
Base.getproperty(r::Row, nm::Symbol) = getindex(r, getcursor(r).lookup[nm])
96+
Tables.getcolumn(r::Row, i::Int) = Tables.getcolumn(r, getcursor(r).types[i], i, getcursor(r).names[i])
97+
Tables.getcolumn(r::Row, nm::Symbol) = Tables.getcolumn(r, getcursor(r).lookup[nm])
10098

101-
Tables.istable(::Type{<:Cursor}) = true
102-
Tables.rowaccess(::Type{<:Cursor}) = true
103-
Tables.rows(q::Cursor) = q
99+
Tables.isrowtable(::Type{<:Cursor}) = true
104100
Tables.schema(c::Cursor) = Tables.Schema(c.names, c.types)
105101

106102
Base.eltype(c::Cursor) = Row
@@ -126,27 +122,32 @@ function DBInterface.lastrowid(c::Cursor)
126122
return API.insertid(c.stmt)
127123
end
128124

129-
@noinline kwcheck(kw) = !isempty(kw) && throw(MySQLInterfaceError("named parameters not supported by mysql; parameters must be provided in order by position; e.g. `DBInterface.execute!(stmt, param1, param2)`"))
125+
"""
126+
DBInterface.close!(cursor)
127+
128+
Close a cursor. No more results will be available.
129+
"""
130+
DBInterface.close!(c::Cursor) = clear!(c.conn)
131+
130132
@noinline paramcheck(stmt, args) = length(args) == stmt.nparams || throw(MySQLInterfaceError("stmt requires $(stmt.nparams) params, only $(length(args)) provided"))
131133

132134
"""
133-
DBInterface.execute!(stmt, args...; mysql_store_result=true) => MySQL.Cursor
135+
DBInterface.execute(stmt, params; mysql_store_result=true) => MySQL.Cursor
134136
135-
Execute a prepared statement, optionally passing `args` to be bound as parameters (like `?` in the sql).
137+
Execute a prepared statement, optionally passing `params` to be bound as parameters (like `?` in the sql).
136138
Returns a `Cursor` object, which iterates resultset rows and satisfies the `Tables.jl` interface, meaning
137139
results can be sent to any valid sink function (`DataFrame(cursor)`, `CSV.write("results.csv", cursor)`, etc.).
138140
Specifying `mysql_store_result=false` will avoid buffering the full resultset to the client after executing
139141
the query, which has memory use advantages, though ties up the database server since resultset rows must be
140142
fetched one at a time.
141143
"""
142-
function DBInterface.execute!(stmt::Statement, args...; mysql_store_result::Bool=true, kw...)
144+
function DBInterface.execute(stmt::Statement, params=(); mysql_store_result::Bool=true)
143145
checkstmt(stmt)
144-
kwcheck(kw)
145-
paramcheck(stmt, args)
146+
paramcheck(stmt, params)
146147
clear!(stmt.conn)
147-
if length(args) > 0
148+
if length(params) > 0
148149
foreach(1:stmt.nparams) do i
149-
bind!(stmt.bindhelpers[i], stmt.binds, i, args[i])
150+
bind!(stmt.bindhelpers[i], stmt.binds, i, params[i])
150151
end
151152
API.bindparam(stmt.stmt, stmt.binds)
152153
end

test/runtests.jl

+20-20
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ DBInterface.close!(conn)
66
# load host/user + options from file
77
conn = DBInterface.connect(MySQL.Connection, "", "", ""; option_file="my.ini")
88

9-
DBInterface.execute!(conn, "DROP DATABASE if exists mysqltest")
10-
DBInterface.execute!(conn, "CREATE DATABASE mysqltest")
11-
DBInterface.execute!(conn, "use mysqltest")
12-
DBInterface.execute!(conn, """CREATE TABLE Employee
9+
DBInterface.execute(conn, "DROP DATABASE if exists mysqltest")
10+
DBInterface.execute(conn, "CREATE DATABASE mysqltest")
11+
DBInterface.execute(conn, "use mysqltest")
12+
DBInterface.execute(conn, """CREATE TABLE Employee
1313
(
1414
ID INT NOT NULL AUTO_INCREMENT,
1515
OfficeNo TINYINT,
@@ -30,7 +30,7 @@ DBInterface.execute!(conn, """CREATE TABLE Employee
3030
PRIMARY KEY (ID)
3131
);""")
3232

33-
DBInterface.execute!(conn, """INSERT INTO Employee (OfficeNo, DeptNo, EmpNo, Wage, Salary, Rate, LunchTime, JoinDate, LastLogin, LastLogin2, Initial, Name, Photo, JobType, Senior)
33+
DBInterface.execute(conn, """INSERT INTO Employee (OfficeNo, DeptNo, EmpNo, Wage, Salary, Rate, LunchTime, JoinDate, LastLogin, LastLogin2, Initial, Name, Photo, JobType, Senior)
3434
VALUES
3535
(1, 2, 1301, 3.14, 10000.50, 1.001, '12:00:00', '2015-8-3', '2015-9-5 12:31:30', '2015-9-5 12:31:30', 'A', 'John', 'abc', 'HR', b'1'),
3636
(1, 2, 1422, 3.14, 20000.25, 2.002, '13:00:00', '2015-8-4', '2015-10-12 13:12:14', '2015-10-12 13:12:14', 'B', 'Tom', 'def', 'HR', b'1'),
@@ -57,7 +57,7 @@ expected = (
5757
Senior = Union{Missing, MySQL.API.Bit}[MySQL.API.Bit(1), MySQL.API.Bit(1), MySQL.API.Bit(0), MySQL.API.Bit(1)],
5858
)
5959

60-
cursor = DBInterface.execute!(conn, "select * from Employee")
60+
cursor = DBInterface.execute(conn, "select * from Employee")
6161
@test DBInterface.lastrowid(cursor) == 1
6262
@test eltype(cursor) == MySQL.TextRow
6363
@test Tables.istable(cursor)
@@ -75,14 +75,14 @@ for (i, prop) in enumerate(propertynames(row))
7575
@test getproperty(row, prop) == row[prop] == row[i] == expected[prop][1]
7676
end
7777

78-
res = DBInterface.execute!(conn, "select * from Employee") |> columntable
78+
res = DBInterface.execute(conn, "select * from Employee") |> columntable
7979
@test length(res) == 16
8080
@test length(res[1]) == 4
8181
@test res == expected
8282

8383
# as a prepared statement
8484
stmt = DBInterface.prepare(conn, "select * from Employee")
85-
cursor = DBInterface.execute!(stmt)
85+
cursor = DBInterface.execute(stmt)
8686
@test DBInterface.lastrowid(cursor) == 1
8787
@test eltype(cursor) == MySQL.Row
8888
@test Tables.istable(cursor)
@@ -100,15 +100,15 @@ for (i, prop) in enumerate(propertynames(row))
100100
@test getproperty(row, prop) == row[prop] == row[i] == expected[prop][1]
101101
end
102102

103-
res = DBInterface.execute!(stmt) |> columntable
103+
res = DBInterface.execute(stmt) |> columntable
104104
@test length(res) == 16
105105
@test length(res[1]) == 4
106106
@test res == expected
107107

108108
@test DBInterface.close!(stmt) === nothing
109109

110110
# insert null row
111-
DBInterface.execute!(conn, "INSERT INTO Employee () VALUES ();")
111+
DBInterface.execute(conn, "INSERT INTO Employee () VALUES ();")
112112
for i = 1:length(expected)
113113
if i == 1
114114
push!(expected[i], 5)
@@ -118,7 +118,7 @@ for i = 1:length(expected)
118118
end
119119
end
120120

121-
res = DBInterface.execute!(conn, "select * from Employee") |> columntable
121+
res = DBInterface.execute(conn, "select * from Employee") |> columntable
122122
@test length(res) == 16
123123
@test length(res[1]) == 5
124124
for i = 1:length(expected)
@@ -128,7 +128,7 @@ for i = 1:length(expected)
128128
end
129129

130130
stmt = DBInterface.prepare(conn, "select * from Employee")
131-
res = DBInterface.execute!(stmt) |> columntable
131+
res = DBInterface.execute(stmt) |> columntable
132132
DBInterface.close!(stmt)
133133
@test length(res) == 16
134134
@test length(res[1]) == 5
@@ -139,7 +139,7 @@ for i = 1:length(expected)
139139
end
140140

141141
# now test insert/parameter binding
142-
DBInterface.execute!(conn, "DELETE FROM Employee")
142+
DBInterface.execute(conn, "DELETE FROM Employee")
143143
for i = 1:length(expected)
144144
if i != 11
145145
pop!(expected[i])
@@ -150,10 +150,10 @@ stmt = DBInterface.prepare(conn,
150150
"INSERT INTO Employee (OfficeNo, DeptNo, EmpNo, Wage, Salary, Rate, LunchTime, JoinDate, LastLogin, LastLogin2, Initial, Name, Photo, JobType, Senior)
151151
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
152152

153-
DBInterface.executemany!(stmt, Base.structdiff(expected, NamedTuple{(:ID,)})...)
153+
DBInterface.executemany(stmt, Base.structdiff(expected, NamedTuple{(:ID,)}))
154154

155155
stmt2 = DBInterface.prepare(conn, "select * from Employee")
156-
res = DBInterface.execute!(stmt2) |> columntable
156+
res = DBInterface.execute(stmt2) |> columntable
157157
DBInterface.close!(stmt2)
158158
@test length(res) == 16
159159
@test length(res[1]) == 4
@@ -163,11 +163,11 @@ for i = 1:length(expected)
163163
end
164164
end
165165

166-
DBInterface.execute!(stmt, missing, missing, missing, missing, missing, missing, missing, missing, missing, DateTime("2015-09-05T12:31:30"), missing, missing, missing, missing, missing)
166+
DBInterface.execute(stmt, [missing, missing, missing, missing, missing, missing, missing, missing, missing, DateTime("2015-09-05T12:31:30"), missing, missing, missing, missing, missing])
167167
DBInterface.close!(stmt)
168168

169169
stmt = DBInterface.prepare(conn, "select * from Employee")
170-
res = DBInterface.execute!(stmt) |> columntable
170+
res = DBInterface.execute(stmt) |> columntable
171171
DBInterface.close!(stmt)
172172
for i = 1:length(expected)
173173
if i != 11 && i != 1
@@ -176,20 +176,20 @@ for i = 1:length(expected)
176176
end
177177

178178
# mysql_use_result
179-
res = DBInterface.execute!(conn, "select DeptNo, OfficeNo from Employee"; mysql_store_result=false) |> columntable
179+
res = DBInterface.execute(conn, "select DeptNo, OfficeNo from Employee"; mysql_store_result=false) |> columntable
180180
@test length(res) == 2
181181
@test length(res[1]) == 5
182182
@test isequal(res.OfficeNo, [1, 1, 1, 1, missing])
183183

184184
stmt = DBInterface.prepare(conn, "select DeptNo, OfficeNo from Employee")
185-
res = DBInterface.execute!(stmt; mysql_store_result=false) |> columntable
185+
res = DBInterface.execute(stmt; mysql_store_result=false) |> columntable
186186
DBInterface.close!(stmt)
187187
@test length(res) == 2
188188
@test length(res[1]) == 5
189189
@test isequal(res.OfficeNo, [1, 1, 1, 1, missing])
190190

191191
stmt = DBInterface.prepare(conn, "select DeptNo, OfficeNo from Employee where OfficeNo = ?")
192-
res = DBInterface.execute!(stmt, 1; mysql_store_result=false) |> columntable
192+
res = DBInterface.execute(stmt, 1; mysql_store_result=false) |> columntable
193193
DBInterface.close!(stmt)
194194
@test length(res) == 2
195195
@test length(res[1]) == 4

0 commit comments

Comments
 (0)