|
1 | 1 | __precompile__(true)
|
2 | 2 | module MySQL
|
3 |
| - using Compat |
4 |
| - using DataFrames |
5 |
| - using Missings |
6 |
| - using Compat.Dates |
7 |
| - |
8 |
| - include("config.jl") |
9 |
| - include("consts.jl") |
10 |
| - include("types.jl") |
11 |
| - include("datetime.jl") |
12 |
| - include("api.jl") |
13 |
| - include("results.jl") |
14 |
| - include("iterators.jl") |
15 |
| - include("handy.jl") |
| 3 | +using Compat, Compat.Dates |
| 4 | +using DataStreams, Missings |
| 5 | + |
| 6 | +export Data |
| 7 | + |
| 8 | +@static if isdefined(Core, :NamedTuple) |
| 9 | + macro NT(args...) |
| 10 | + return esc(:(($(args...),))) |
| 11 | + end |
| 12 | +else |
| 13 | + using NamedTuples |
16 | 14 | end
|
| 15 | + |
| 16 | +abstract type MySQLError end |
| 17 | +# For errors that happen in MySQL.jl |
| 18 | +mutable struct MySQLInterfaceError <: MySQLError |
| 19 | + msg::String |
| 20 | +end |
| 21 | +Base.showerror(io::IO, e::MySQLInterfaceError) = print(io, e.msg) |
| 22 | + |
| 23 | +include("api.jl") |
| 24 | +using .API |
| 25 | + |
| 26 | +include("types.jl") |
| 27 | + |
| 28 | +function setoptions!(ptr, opts) |
| 29 | + ptr == C_NULL && throw(MySQLInterfaceError("`MySQL.setoptions!` called with NULL connection.")) |
| 30 | + for (k, v) in opts |
| 31 | + val = API.mysql_options(ptr, k, v) |
| 32 | + val != 0 && throw(MySQLInternalError(ptr)) |
| 33 | + end |
| 34 | + nothing |
| 35 | +end |
| 36 | + |
| 37 | +""" |
| 38 | + MySQL.connect(host::String, user::String, passwd::String; db::String = "", port = "3306", socket::String = MySQL.API.MYSQL_DEFAULT_SOCKET, opts = Dict()) |
| 39 | +
|
| 40 | +Connect to a MySQL database. |
| 41 | +""" |
| 42 | +function connect(host::String, user::String, passwd::String; db::String="", port::Integer=3306, unix_socket::String=API.MYSQL_DEFAULT_SOCKET, client_flag=API.CLIENT_MULTI_STATEMENTS, opts = Dict()) |
| 43 | + _ptr = C_NULL |
| 44 | + _ptr = API.mysql_init(_ptr) |
| 45 | + _ptr == C_NULL && throw(MySQLInterfaceError("Failed to initialize MySQL database")) |
| 46 | + setoptions!(_ptr, opts) |
| 47 | + ptr = API.mysql_real_connect(_ptr, host, user, passwd, |
| 48 | + db, UInt32(port), unix_socket, client_flag) |
| 49 | + ptr == C_NULL && throw(MySQLInternalError(_ptr)) |
| 50 | + return Connection(ptr, host, string(port), user, db) |
| 51 | +end |
| 52 | + |
| 53 | +""" |
| 54 | + MySQL.disconnect(conn::MySQL.Connection) |
| 55 | +
|
| 56 | +Close a handle to a MySQL database opened by `MySQL.connect`. |
| 57 | +""" |
| 58 | +function disconnect(conn::Connection) |
| 59 | + conn.ptr == C_NULL && throw(MySQLInterfaceError("Method called with NULL connection.")) |
| 60 | + API.mysql_close(conn.ptr) |
| 61 | + conn.ptr = C_NULL |
| 62 | + conn.host = "" |
| 63 | + conn.user = "" |
| 64 | + conn.db = "" |
| 65 | + return nothing |
| 66 | +end |
| 67 | + |
| 68 | +function insertid(conn::Connection) |
| 69 | + conn.ptr == C_NULL && throw(MySQLInterfaceError("MySQL.insertid called with NULL connection.")) |
| 70 | + return API.mysql_insert_id(conn.ptr) |
| 71 | +end |
| 72 | + |
| 73 | +""" |
| 74 | + MySQL.escape(conn::MySQL.Connection, str::String) -> String |
| 75 | +
|
| 76 | +Escapes a string using `mysql_real_escape_string()`, returns the escaped string. |
| 77 | +""" |
| 78 | +function escape(conn::MySQL.Connection, str::String) |
| 79 | + output = Vector{UInt8}(uninitialized, length(str) * 2 + 1) |
| 80 | + output_len = API.mysql_real_escape_string(conn.ptr, output, str, Culong(length(str))) |
| 81 | + if output_len == typemax(Cuint) |
| 82 | + throw(MySQLInternalError(conn)) |
| 83 | + end |
| 84 | + return String(output[1:output_len]) |
| 85 | +end |
| 86 | + |
| 87 | +""" |
| 88 | + MySQL.execute!(conn, sql) => Void |
| 89 | +
|
| 90 | +execute an sql statement without returning results (useful for DDL statements, update, delete, etc.) |
| 91 | +""" |
| 92 | +function execute!(conn::Connection, sql::String) |
| 93 | + conn.ptr == C_NULL && throw(MySQLInterfaceError("`MySQL.execute!` called with NULL connection.")) |
| 94 | + API.mysql_query(conn.ptr, sql) == 0 || throw(MySQLInternalError(conn)) |
| 95 | + return API.mysql_affected_rows(conn.ptr) |
| 96 | +end |
| 97 | + |
| 98 | +""" |
| 99 | + MySQL.query(conn, sql, sink=Data.Table; append::Bool=false) => sink |
| 100 | +
|
| 101 | +execute an sql statement and return the results in `sink`, which can be any valid `Data.Sink` (interface from DataStreams.jl). By default, a NamedTuple of Vectors are returned. |
| 102 | +
|
| 103 | +Passing `append=true` as a keyword argument will cause the resultset to be _appended_ to the sink instead of replacing. |
| 104 | +""" |
| 105 | +function query end |
| 106 | + |
| 107 | +function query(conn::Connection, sql::String, sink::Type=Data.Table, args...; append::Bool=false, kwargs...) |
| 108 | + source = Query(conn, sql; kwargs...) |
| 109 | + sink = Data.stream!(source, sink, args...; append=append) |
| 110 | + return Data.close!(sink) |
| 111 | +end |
| 112 | + |
| 113 | +function query(conn::Connection, sql::String, sink::T; append::Bool=false, kwargs...) where {T} |
| 114 | + source = Query(conn, sql; kwargs...) |
| 115 | + sink = Data.stream!(source, sink; append=append) |
| 116 | + return Data.close!(sink) |
| 117 | +end |
| 118 | + |
| 119 | +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)) |
| 120 | +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)) |
| 121 | + |
| 122 | +include("prepared.jl") |
| 123 | + |
| 124 | +Base.@deprecate mysql_options MySQL.setoptions! |
| 125 | +Base.@deprecate mysql_connect MySQL.connect |
| 126 | +Base.@deprecate mysql_disconnect MySQL.disconnect |
| 127 | +Base.@deprecate mysql_insert_id MySQL.insertid |
| 128 | + |
| 129 | +end # module |
0 commit comments