@@ -48,7 +48,9 @@ function metadata(result::API.MYSQL_RES)
4848 return unsafe_wrap (Array, rawfields, nfields)
4949end
5050
51- mutable struct Query{hasresult, names, T}
51+ # resulttype is a symbol with values :none :streaming :default
52+ # names and types relate to the returned columns in the query
53+ mutable struct Query{resulttype, names, T}
5254 result:: Result
5355 ptr:: Ptr{Ptr{Int8}}
5456 ncols:: Int
@@ -62,39 +64,51 @@ function julia_type(field_type, notnullable, isunsigned)
6264end
6365
6466"""
65- MySQL.Query(conn, sql, sink=Data.Table ; kwargs...) => MySQL.Query
67+ MySQL.Query(conn, sql; kwargs...) => MySQL.Query
6668
6769Execute an SQL statement and return a `MySQL.Query` object. Result rows can be
68- iterated as NamedTuples via `Data .rows(query)` where `query` is the `MySQL.Query`
70+ iterated as NamedTuples via `Table .rows(query)` where `query` is the `MySQL.Query`
6971object.
7072
71- To materialize the results as a `DataFrame`, use `MySQL.query(conn, sql) |> DataFrame`.
73+ Supported Key Word Arguments:
74+ * `streaming` - Defaults to false. If true, length of the result size is unknown as the result is returned row by row. May be more memory efficient.
75+
76+ To materialize the results as a `DataFrame`, use `MySQL.Query(conn, sql) |> DataFrame`.
7277"""
73- function Query (conn:: Connection , sql:: String ; kwargs... )
78+ function Query (conn:: Connection , sql:: String ; streaming :: Bool = false , kwargs... )
7479 conn. ptr == C_NULL && throw (MySQLInterfaceError (" Method called with null connection." ))
7580 MySQL. API. mysql_query (conn. ptr, sql) != 0 && throw (MySQLInternalError (conn))
76- result = MySQL. Result (MySQL. API. mysql_store_result (conn. ptr))
81+
82+ if streaming
83+ resulttype = :streaming
84+ result = MySQL. Result (MySQL. API. mysql_use_result (conn. ptr))
85+ else
86+ resulttype = :default
87+ result = result = MySQL. Result (MySQL. API. mysql_store_result (conn. ptr))
88+ end
89+
7790 if result. ptr != C_NULL
7891 nrows = MySQL. API. mysql_num_rows (result. ptr)
7992 fields = MySQL. metadata (result. ptr)
8093 names = Tuple (ccall (:jl_symbol_n , Ref{Symbol}, (Ptr{UInt8}, Csize_t), x. name, x. name_length) for x in fields)
8194 T = Tuple{(julia_type (x. field_type, API. notnullable (x), API. isunsigned (x)) for x in fields). .. }
82- hasresult = true
8395 ncols = length (fields)
8496 ptr = MySQL. API. mysql_fetch_row (result. ptr)
8597 elseif API. mysql_field_count (conn. ptr) == 0
8698 result = Result (Int (API. mysql_affected_rows (conn. ptr)))
8799 nrows = ncols = 1
88100 names = (:num_rows_affected ,)
89101 T = Tuple{Int}
90- hasresult = false
102+ resulttype = :none
91103 ptr = C_NULL
92104 else
93105 throw (MySQLInterfaceError (" Query expected to produce results but did not." ))
94106 end
95- return Query {hasresult , names, T} (result, ptr, ncols, nrows)
107+ return Query {resulttype , names, T} (result, ptr, ncols, nrows)
96108end
97109
110+ Base. IteratorSize (:: Type{Query{resulttype, names, T}} ) where {resulttype, names, T} = resulttype == :streaming ? Base. SizeUnknown () : Base. HasLength ()
111+
98112Tables. istable (:: Type{<:Query} ) = true
99113Tables. rowaccess (:: Type{<:Query} ) = true
100114Tables. rows (q:: Query ) = q
@@ -126,9 +140,8 @@ function generate_namedtuple(::Type{NamedTuple{names, types}}, q) where {names,
126140 end
127141end
128142
129- function Base. iterate (q:: Query{hasresult, names, types} , st= 1 ) where {hasresult, names, types}
130- st > length (q) && return nothing
131- ! hasresult && return (num_rows_affected= Int (q. result. ptr),), 2
143+ function Base. iterate (q:: Query{resulttype, names, types} , st= 1 ) where {resulttype, names, types}
144+ st == 1 && resulttype == :none && return (num_rows_affected= Int (q. result. ptr),), 2
132145 q. ptr == C_NULL && return nothing
133146 nt = generate_namedtuple (NamedTuple{names, types}, q)
134147 q. ptr = API. mysql_fetch_row (q. result. ptr)
0 commit comments