4
4
Independently constructs an `SQLite.Source` in `db` with the SQL statement `sql`.
5
5
Will bind `values` to any parameters in `sql`.
6
6
`rows` is used to indicate how many rows to return in the query result if known beforehand. `rows=0` (the default) will return all possible rows.
7
- `stricttypes=false` will remove strict column typing in the result set, making each column effectively `Vector{Any}`
7
+ `stricttypes=false` will remove strict column typing in the result set, making each column effectively `Vector{Any}`. `nullable::Bool=true` indicates
8
+ whether to allow null values when fetching results; if set to `false` and a null value is encountered, a `NullException` will be thrown.
8
9
9
10
Note that no results are returned; `sql` is executed, and results are ready to be returned (i.e. streamed to an appropriate `Data.Sink` type)
10
11
"""
11
- function Source (db:: DB , sql:: AbstractString , values= []; rows:: Int = - 1 , stricttypes:: Bool = true )
12
- stmt = SQLite. Stmt (db,sql)
12
+ function Source (db:: DB , sql:: AbstractString , values= []; rows:: Int = - 1 , stricttypes:: Bool = true , nullable :: Bool = true )
13
+ stmt = SQLite. Stmt (db, sql)
13
14
bind! (stmt, values)
14
15
status = SQLite. execute! (stmt)
15
16
cols = SQLite. sqlite3_column_count (stmt. handle)
16
- header = Array (String,cols)
17
- types = Array (DataType,cols)
17
+ header = Array (String, cols)
18
+ types = Array (DataType, cols)
18
19
for i = 1 : cols
19
- header[i] = unsafe_string (SQLite. sqlite3_column_name (stmt. handle,i))
20
+ header[i] = unsafe_string (SQLite. sqlite3_column_name (stmt. handle, i))
20
21
# do better column type inference; query what the column was created for?
21
- types[i] = stricttypes ? SQLite. juliatype (stmt. handle,i) : Any
22
+ if nullable
23
+ types[i] = Nullable{stricttypes ? SQLite. juliatype (stmt. handle, i) : Any}
24
+ else
25
+ types[i] = stricttypes ? SQLite. juliatype (stmt. handle, i) : Any
26
+ end
22
27
end
23
- return SQLite. Source (Data. Schema (header,types,rows),stmt,status)
28
+ return SQLite. Source (Data. Schema (header, types, rows), stmt, status)
24
29
end
25
30
26
31
"""
@@ -31,25 +36,25 @@ constructs an SQLite.Source from an SQLite.Sink; selects all rows/columns from t
31
36
Source (sink:: SQLite.Sink ,sql:: AbstractString = " select * from $(sink. tablename) " ) = Source (sink. db, sql:: AbstractString )
32
37
33
38
function juliatype (handle,col)
34
- x = SQLite. sqlite3_column_type (handle,col)
39
+ x = SQLite. sqlite3_column_type (handle, col)
35
40
if x == SQLITE_BLOB
36
- val = sqlitevalue (Any,handle,col)
41
+ val = sqlitevalue (Any,handle, col)
37
42
return typeof (val)
38
43
else
39
44
return juliatype (x)
40
45
end
41
46
end
42
47
juliatype (x) = x == SQLITE_INTEGER ? Int : x == SQLITE_FLOAT ? Float64 : x == SQLITE_TEXT ? String : Any
43
48
44
- sqlitevalue {T<:Union{Signed,Unsigned}} (:: Type{T} ,handle,col) = convert (T, sqlite3_column_int64 (handle,col))
45
- const FLOAT_TYPES = Union{Float16,Float32,Float64} # exclude BigFloat
46
- sqlitevalue {T<:FLOAT_TYPES} (:: Type{T} ,handle,col) = convert (T, sqlite3_column_double (handle,col))
49
+ sqlitevalue {T<:Union{Signed,Unsigned}} (:: Type{T} , handle, col) = convert (T, sqlite3_column_int64 (handle, col))
50
+ const FLOAT_TYPES = Union{Float16, Float32, Float64} # exclude BigFloat
51
+ sqlitevalue {T<:FLOAT_TYPES} (:: Type{T} , handle, col) = convert (T, sqlite3_column_double (handle, col))
47
52
# TODO : test returning a WeakRefString instead of calling `bytestring`
48
- sqlitevalue {T<:AbstractString} (:: Type{T} ,handle,col) = convert (T,unsafe_string (sqlite3_column_text (handle,col)))
49
- function sqlitevalue {T} (:: Type{T} ,handle,col)
50
- blob = convert (Ptr{UInt8},sqlite3_column_blob (handle,col))
51
- b = sqlite3_column_bytes (handle,col)
52
- buf = zeros (UInt8,b) # global const?
53
+ sqlitevalue {T<:AbstractString} (:: Type{T} , handle, col) = convert (T,unsafe_string (sqlite3_column_text (handle, col)))
54
+ function sqlitevalue {T} (:: Type{T} , handle, col)
55
+ blob = convert (Ptr{UInt8}, sqlite3_column_blob (handle, col))
56
+ b = sqlite3_column_bytes (handle, col)
57
+ buf = zeros (UInt8, b) # global const?
53
58
unsafe_copy! (pointer (buf), blob, b)
54
59
r = sqldeserialize (buf):: T
55
60
return r
@@ -67,14 +72,26 @@ Data.streamtype{T<:SQLite.Source}(::Type{T}, ::Type{Data.Field}) = true
67
72
# `T` might be Int, Float64, String, WeakRefString, any Julia type, Any, NullType
68
73
# `t` (the actual type of the value we're returning), might be SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB, SQLITE_NULL
69
74
# `SQLite.getfield` returns the next `Nullable{T}` value from the `SQLite.Source`
70
- function Data. getfield {T} (source:: SQLite.Source , :: Type{T } , row, col)
75
+ function Data. getfield {T} (source:: SQLite.Source , :: Type{Nullable{T} } , row, col)
71
76
handle = source. stmt. handle
72
- t = SQLite. sqlite3_column_type (handle,col)
77
+ t = SQLite. sqlite3_column_type (handle, col)
73
78
if t == SQLite. SQLITE_NULL
74
79
val = Nullable {T} ()
75
80
else
76
81
TT = SQLite. juliatype (t) # native SQLite Int, Float, and Text types
77
- val = Nullable {T} (sqlitevalue (ifelse (TT === Any && ! isbits (T), T, TT),handle,col))
82
+ val = Nullable {T} (sqlitevalue (ifelse (TT === Any && ! isbits (T), T, TT), handle, col))
83
+ end
84
+ col == source. schema. cols && (source. status = sqlite3_step (handle))
85
+ return val
86
+ end
87
+ function Data. getfield {T} (source:: SQLite.Source , :: Type{T} , row, col)
88
+ handle = source. stmt. handle
89
+ t = SQLite. sqlite3_column_type (handle, col)
90
+ if t == SQLite. SQLITE_NULL
91
+ throw (NullException)
92
+ else
93
+ TT = SQLite. juliatype (t) # native SQLite Int, Float, and Text types
94
+ val = sqlitevalue (ifelse (TT === Any && ! isbits (T), T, TT), handle, col)
78
95
end
79
96
col == source. schema. cols && (source. status = sqlite3_step (handle))
80
97
return val
@@ -89,13 +106,13 @@ Will bind `values` to any parameters in `sql`.
89
106
`rows` is used to indicate how many rows to return in the query result if known beforehand. `rows=0` (the default) will return all possible rows.
90
107
`stricttypes=false` will remove strict column typing in the result set, making each column effectively `Vector{Any}`
91
108
"""
92
- function query (db:: DB , sql:: AbstractString , sink= DataFrame, args... ; append:: Bool = false , values= [], rows:: Int = - 1 , stricttypes:: Bool = true )
93
- source = Source (db, sql, values; rows= rows, stricttypes= stricttypes)
109
+ function query (db:: DB , sql:: AbstractString , sink= DataFrame, args... ; append:: Bool = false , values= [], rows:: Int = - 1 , stricttypes:: Bool = true , nullable :: Bool = true )
110
+ source = Source (db, sql, values; rows= rows, stricttypes= stricttypes, nullable = nullable )
94
111
return Data. stream! (source, sink, append, args... )
95
112
end
96
113
97
- function query {T} (db:: DB , sql:: AbstractString , sink:: T ; append:: Bool = false , values= [], rows:: Int = - 1 , stricttypes:: Bool = true )
98
- source = Source (db, sql, values; rows= rows, stricttypes= stricttypes)
114
+ function query {T} (db:: DB , sql:: AbstractString , sink:: T ; append:: Bool = false , values= [], rows:: Int = - 1 , stricttypes:: Bool = true , nullable :: Bool = true )
115
+ source = Source (db, sql, values; rows= rows, stricttypes= stricttypes, nullable = nullable )
99
116
return Data. stream! (source, sink, append)
100
117
end
101
118
query (source:: SQLite.Source , sink= DataFrame, args... ; append:: Bool = false ) = Data. stream! (source, sink, append, args... )
0 commit comments