Skip to content

Commit 8fed199

Browse files
authored
Fix and test strict keyword. (#346)
Fixes type stability issues with the strict keyword. Thanks @evetion!
1 parent ccdb8b0 commit 8fed199

File tree

3 files changed

+65
-15
lines changed

3 files changed

+65
-15
lines changed

src/SQLite.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ mutable struct Stmt <: DBInterface.Statement
154154
end
155155
end
156156

157-
_get_stmt_handle(stmt::Stmt) = stmt.stmt_wrapper[]
157+
_get_stmt_handle(stmt::Stmt)::StmtHandle = stmt.stmt_wrapper[]
158158
function _set_stmt_handle(stmt::Stmt, handle)
159159
stmt.stmt_wrapper[] = handle
160160
end
@@ -494,15 +494,15 @@ function sqlitevalue(
494494
::Type{T},
495495
handle,
496496
col,
497-
) where {T<:Union{Base.BitSigned,Base.BitUnsigned}}
497+
)::T where {T<:Union{Base.BitSigned,Base.BitUnsigned}}
498498
convert(T, C.sqlite3_column_int64(handle, col - 1))
499499
end
500500
const FLOAT_TYPES = Union{Float16,Float32,Float64} # exclude BigFloat
501-
function sqlitevalue(::Type{T}, handle, col) where {T<:FLOAT_TYPES}
501+
function sqlitevalue(::Type{T}, handle, col)::T where {T<:FLOAT_TYPES}
502502
convert(T, C.sqlite3_column_double(handle, col - 1))
503503
end
504504
#TODO: test returning a WeakRefString instead of calling `unsafe_string`
505-
function sqlitevalue(::Type{T}, handle, col) where {T<:AbstractString}
505+
function sqlitevalue(::Type{T}, handle, col)::T where {T<:AbstractString}
506506
convert(T, unsafe_string(C.sqlite3_column_text(handle, col - 1)))
507507
end
508508
function sqlitevalue(::Type{T}, handle, col) where {T}

src/tables.jl

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,26 +78,34 @@ end
7878
end
7979

8080
function getvalue(
81-
q::Query{strict},
81+
q::Query{true},
8282
col::Int,
8383
rownumber::Int,
8484
::Type{T},
85-
) where {strict,T}
85+
)::Union{Missing,nonmissingtype(T)} where {T}
86+
rownumber == q.current_rownumber[] || wrongrow(rownumber)
87+
handle = _get_stmt_handle(q.stmt)
88+
t = C.sqlite3_column_type(handle, col - 1)
89+
if t == C.SQLITE_NULL
90+
return missing
91+
end
92+
sqlitevalue(nonmissingtype(T), handle, col)
93+
end
94+
95+
function getvalue(
96+
q::Query{false},
97+
col::Int,
98+
rownumber::Int,
99+
::Type{T},
100+
) where {T}
86101
rownumber == q.current_rownumber[] || wrongrow(rownumber)
87102
handle = _get_stmt_handle(q.stmt)
88103
t = C.sqlite3_column_type(handle, col - 1)
89104
if t == C.SQLITE_NULL
90105
return missing
91-
elseif strict
92-
return sqlitevalue(T, handle, col)
93-
else
94-
TT = juliatype(t) # native SQLite Int, Float, and Text types
95-
return sqlitevalue(
96-
ifelse(TT === Any && !isbitstype(T), T, TT),
97-
handle,
98-
col,
99-
)
100106
end
107+
TT = juliatype(t) # native SQLite Int, Float, and Text types
108+
return sqlitevalue(ifelse(TT === Any && !isbitstype(T), T, TT), handle, col)
101109
end
102110

103111
function Tables.getcolumn(r::Row, ::Type{T}, i::Int, nm::Symbol) where {T}

test/runtests.jl

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,48 @@ end
10171017
tbl = DBInterface.execute(db, "select x from tmp") |> columntable
10181018
@test isequal(tbl.x, [missing, :a])
10191019

1020+
# Symbol in TEXT type doesn't work
1021+
# when strict and first row is NULL
1022+
tbl =
1023+
DBInterface.execute(
1024+
DBInterface.prepare(db, "select x from tmp"),
1025+
();
1026+
strict = true,
1027+
) |> columntable
1028+
@test isequal(tbl.x, [missing, "7JL\x1e\x04"])
1029+
1030+
# Symbol in BLOB type does work strict
1031+
db = SQLite.DB()
1032+
DBInterface.execute(db, "create table tmp ( x BLOB )")
1033+
DBInterface.execute(db, "insert into tmp values (?)", (nothing,))
1034+
DBInterface.execute(db, "insert into tmp values (?)", (:a,))
1035+
tbl = DBInterface.execute(db, "select x from tmp") |> columntable
1036+
@test isequal(tbl.x, [missing, :a])
1037+
1038+
tbl =
1039+
DBInterface.execute(
1040+
DBInterface.prepare(db, "select x from tmp"),
1041+
();
1042+
strict = true,
1043+
) |> columntable
1044+
@test isequal(tbl.x, [missing, :a])
1045+
1046+
# Symbol in TEXT always works when first row is not NULL
1047+
db = SQLite.DB()
1048+
DBInterface.execute(db, "create table tmp ( x TEXT )")
1049+
DBInterface.execute(db, "insert into tmp values (?)", (:a,))
1050+
DBInterface.execute(db, "insert into tmp values (?)", (nothing,))
1051+
tbl = DBInterface.execute(db, "select x from tmp") |> columntable
1052+
@test isequal(tbl.x, [:a, missing])
1053+
1054+
tbl =
1055+
DBInterface.execute(
1056+
DBInterface.prepare(db, "select x from tmp"),
1057+
();
1058+
strict = true,
1059+
) |> columntable
1060+
@test isequal(tbl.x, [:a, missing])
1061+
10201062
db = SQLite.DB()
10211063
DBInterface.execute(
10221064
db,

0 commit comments

Comments
 (0)