Skip to content

Commit 808930c

Browse files
authored
Initial Tables.jl implementation (#117)
* Initial Tables.jl implementation * Remove DataStreams, add Tables to REQUIRE, fix tests * Try to fix CI * Remove osx testing for now
1 parent 4d2611e commit 808930c

11 files changed

+89
-587
lines changed

.appveyor.yml

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ platform:
77
- x86 # 32-bit
88
- x64 # 64-bit
99

10+
services:
11+
- mysql
12+
1013
# # Uncomment the following lines to allow failures on nightly julia
1114
# # (tests will run but not make your overall status red)
1215
# matrix:

.travis.yml

-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ services:
66

77
os:
88
- linux
9-
- osx
109

1110
julia:
1211
- 1.0
@@ -24,8 +23,6 @@ after_success:
2423
before_script:
2524
- export OLD_PATH=$LD_LIBRARY_PATH
2625
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`mysql_config --libs | cut -d ' ' -f1 | sed 's/-L//'`
27-
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install mysql ; fi
28-
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mysql.server start ; fi
2926

3027
after_script:
3128
- export LD_LIBRARY_PATH=$OLD_PATH

REQUIRE

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
julia 0.7
2-
DataStreams
3-
Missings
2+
Tables
43
DecFP
54
BinaryProvider

src/MySQL.jl

+33-14
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
module MySQL
22

3-
using DataStreams, Missings, Dates
4-
5-
export Data
3+
using Dates, Tables
64

75
abstract type MySQLError end
86
# For errors that happen in MySQL.jl
@@ -67,8 +65,8 @@ end
6765
Escapes a string using `mysql_real_escape_string()`, returns the escaped string.
6866
"""
6967
function escape(conn::MySQL.Connection, str::String)
70-
output = Vector{UInt8}(undef, length(str) * 2 + 1)
71-
output_len = API.mysql_real_escape_string(conn.ptr, output, str, Culong(length(str)))
68+
output = Vector{UInt8}(undef, sizeof(str) * 2 + 1)
69+
output_len = API.mysql_real_escape_string(conn.ptr, output, str, Culong(sizeof(str)))
7270
if output_len == typemax(Cuint)
7371
throw(MySQLInternalError(conn))
7472
end
@@ -105,20 +103,41 @@ See list of DataStreams implementations [here](https://github.com/JuliaData/Data
105103
"""
106104
function query end
107105

108-
function query(conn::Connection, sql::String, sink::Type=Data.Table, args...; append::Bool=false, kwargs...)
109-
source = Query(conn, sql; kwargs...)
110-
sink = Data.stream!(source, sink, args...; append=append)
111-
return Data.close!(sink)
106+
function query(conn::Connection, sql::String, sink::Union{Type, Nothing}=nothing, args...; append::Bool=false, kwargs...)
107+
if sink === nothing
108+
Base.depwarn("`MySQL.query(conn, sql)` will return a MySQL.Query in the future; to materialize the result, use `MySQL.query(conn, sql) |> columntable` or `MySQL.query(conn, sql) |> DataFrame` instead", nothing)
109+
sink = columntable
110+
else
111+
Base.depwarn("`MySQL.query(conn, sql, $sink)` is deprecated; use `MySQL.query(conn, sql) |> $sink(args...)` instead", nothing)
112+
end
113+
if append
114+
Base.depwarn("`append=true` is deprecated; use sink-specific append features instead. For example, `columntable(existing, MySQL.query(conn, sql))` or `append!(existing_df, MySQL.query(conn, sql))`")
115+
end
116+
return Query(conn, sql; kwargs...) |> sink
112117
end
113118

114119
function query(conn::Connection, sql::String, sink::T; append::Bool=false, kwargs...) where {T}
115-
source = Query(conn, sql; kwargs...)
116-
sink = Data.stream!(source, sink; append=append)
117-
return Data.close!(sink)
120+
Base.depwarn("`MySQL.query(conn, sql, ::$T)` is deprecated; `MySQL.Query` now supports the Tables.jl interface, so any valid Tables.jl sink can receive a resultset", nothing)
121+
if append
122+
Base.depwarn("`append=true` is deprecated; use sink-specific append features instead. For example, `columntable(existing, MySQL.query(conn, sql))` or `append!(existing_df, MySQL.query(conn, sql))`")
123+
end
124+
return Query(conn, sql; kwargs...) |> T
118125
end
119126

120-
query(source::Query, sink=Data.Table, args...; append::Bool=false, transforms::Dict=Dict{Int,Function}()) = (sink = Data.stream!(source, sink, args...; append=append, transforms=transforms); return Data.close!(sink))
121-
query(source::Query, sink::T; append::Bool=false, transforms::Dict=Dict{Int,Function}()) where {T} = (sink = Data.stream!(source, sink; append=append, transforms=transforms); return Data.close!(sink))
127+
function query(source::Query, sink=columntable, args...; append::Bool=false)
128+
Base.depwarn("`MySQL.query(q::MySQL.Query)` is deprecated and will be removed in the future; `MySQL.Query` itself will iterate rows as NamedTuples and supports the Tables.jl interface", nothing)
129+
if append
130+
Base.depwarn("`append=true` is deprecated; use sink-specific append features instead. For example, `columntable(existing, MySQL.query(conn, sql))` or `append!(existing_df, MySQL.query(conn, sql))`")
131+
end
132+
return source |> sink
133+
end
134+
function query(source::Query, sink::T; append::Bool=false) where {T}
135+
Base.depwarn("`MySQL.query(q::MySQL.Query)` is deprecated and will be removed in the future; `MySQL.Query` itself will iterate rows as NamedTuples and supports the Tables.jl interface", nothing)
136+
if append
137+
Base.depwarn("`append=true` is deprecated; use sink-specific append features instead. For example, `columntable(existing, MySQL.query(conn, sql))` or `append!(existing_df, MySQL.query(conn, sql))`")
138+
end
139+
return source |> T
140+
end
122141

123142
include("prepared.jl")
124143

src/api.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module API
22

3-
using Dates, DecFP, Missings
3+
using Dates, DecFP
44

55
# Load libmariadb from our deps.jl
66
const depsjl_path = joinpath(dirname(@__FILE__), "..", "deps", "deps.jl")

src/handy.jl

-141
This file was deleted.

src/iterators.jl

-45
This file was deleted.

src/prepared.jl

+22-11
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,26 @@ function execute!(stmt::Stmt, params=[])
4848
return API.mysql_stmt_affected_rows(stmt.ptr)
4949
end
5050

51-
Data.streamtypes(::Type{Stmt}) = [Data.Row]
52-
function Data.streamto!(sink::Stmt, ::Type{Data.Row}, val, row, col)
53-
sink.rows_affected += execute!(sink, val)
54-
return
55-
end
56-
57-
Stmt(sch::Data.Schema, ::Type{Data.Row}, append::Bool, conn::Connection, sql::String) = Stmt(conn, sql)
58-
Stmt(sink::Stmt, sch::Data.Schema, ::Type{Data.Row}, append::Bool) = sink
51+
execute!(itr, conn::Connection, sql::String) = execute!(itr, Stmt(conn, sql))
52+
function execute!(itr, stmt::Stmt)
53+
rows = Tables.rows(itr)
54+
state = iterate(rows)
55+
state === nothing && return stmt
56+
row, st = state
57+
sch = Tables.Schema(propertynames(row), nothing)
58+
binds = Vector{API.MYSQL_BIND}(undef, stmt.nparams)
59+
bindptr = pointer(binds)
5960

60-
function MySQLStatementIterator(args...)
61-
throw(ArgumentError("`MySQLStatementIterator` is deprecated; instead, you can create a prepared statement by doing `stmt = MySQL.Stmt(conn, sql)` and then \"stream\" parameters to it, with the statement being executed once for each row in the source, like `Data.stream!(source, stmt)`"))
62-
end
61+
while true
62+
Tables.eachcolumn(sch, row) do val, col, nm
63+
binds[col] = bind(val)
64+
end
65+
API.mysql_stmt_bind_param(stmt.ptr, bindptr) == 0 || throw(MySQLStatementError(stmt.ptr))
66+
API.mysql_stmt_execute(stmt.ptr) == 0 || throw(MySQLStatementError(stmt.ptr))
67+
stmt.rows_affected += API.mysql_stmt_affected_rows(stmt.ptr)
68+
state = iterate(rows, st)
69+
state === nothing && break
70+
row, st = state
71+
end
72+
return stmt
73+
end

0 commit comments

Comments
 (0)