Skip to content

Commit f9624b9

Browse files
committed
Scan multiple rows for determining type in strict mode.
1 parent f02bf5a commit f9624b9

2 files changed

Lines changed: 25 additions & 3 deletions

File tree

src/SQLite.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,14 +438,36 @@ end
438438
# get julia type for given column of the given statement
439439
function juliatype(handle, col)
440440
stored_typeid = C.sqlite3_column_type(handle, col - 1)
441+
did_row_scan = false
442+
while stored_typeid == C.SQLITE_NULL
443+
# Scan forward through the rows until we find a non-NULL value for this column
444+
st = C.sqlite3_step(handle)
445+
did_row_scan = true
446+
if st == C.SQLITE_DONE
447+
break
448+
end
449+
stored_typeid = C.sqlite3_column_type(handle, col - 1)
450+
if stored_typeid != C.SQLITE_NULL
451+
break
452+
end
453+
end
441454
if stored_typeid == C.SQLITE_BLOB
442455
# blobs are serialized julia types, so just try to deserialize it
456+
# when forward scanning we need to use the current step to deserialize
443457
deser_val = sqlitevalue(Any, handle, col)
444458
# FIXME deserialized type have priority over declared type, is it fine?
459+
if did_row_scan
460+
C.sqlite3_reset(handle)
461+
C.sqlite3_step(handle)
462+
end
445463
return typeof(deser_val)
446464
else
447465
stored_type = juliatype(stored_typeid)
448466
end
467+
if did_row_scan
468+
C.sqlite3_reset(handle)
469+
C.sqlite3_step(handle)
470+
end
449471
decl_typestr = C.sqlite3_column_decltype(handle, col - 1)
450472
if decl_typestr != C_NULL
451473
return juliatype(unsafe_string(decl_typestr), stored_type)

test/runtests.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,16 +1067,16 @@ end
10671067
tbl = DBInterface.execute(db, "select x from tmp") |> columntable
10681068
@test isequal(tbl.x, [missing, :a])
10691069

1070-
# Symbol in TEXT type doesn't work
1071-
# when strict and first row is NULL (the serialized bytes are interpreted as a string)
1070+
# Symbol in TEXT type now works even when strict and first row is NULL,
1071+
# because juliatype scans multiple rows to find the actual stored type (BLOB)
10721072
tbl =
10731073
DBInterface.execute(
10741074
DBInterface.prepare(db, "select x from tmp"),
10751075
();
10761076
strict = true,
10771077
) |> columntable
10781078
@test tbl.x[1] === missing
1079-
@test tbl.x[2] isa String # Symbol gets incorrectly deserialized as garbage string
1079+
@test tbl.x[2] === :a
10801080

10811081
# Symbol in BLOB type does work strict
10821082
db = SQLite.DB()

0 commit comments

Comments
 (0)