diff --git a/src/tables.jl b/src/tables.jl index fb0b56e..4ff80cb 100644 --- a/src/tables.jl +++ b/src/tables.jl @@ -103,11 +103,12 @@ function getvalue( rownumber == q.current_rownumber[] || wrongrow(rownumber) handle = _get_stmt_handle(q.stmt) t = C.sqlite3_column_type(handle, col - 1) - if t == C.SQLITE_NULL - return missing - end - TT = juliatype(t) # native SQLite Int, Float, and Text types - return sqlitevalue(ifelse(TT === Any && !isbitstype(T), T, TT), handle, col) + # branch on the storage class so each read is a static call + t == C.SQLITE_NULL && return missing + t == C.SQLITE_INTEGER && return C.sqlite3_column_int64(handle, col - 1) + t == C.SQLITE_FLOAT && return C.sqlite3_column_double(handle, col - 1) + t == C.SQLITE_TEXT && return sqlitevalue(String, handle, col) + return sqlitevalue(isbitstype(T) ? Any : T, handle, col) end function Tables.getcolumn(r::Row, ::Type{T}, i::Int, nm::Symbol) where {T} @@ -117,6 +118,8 @@ end function Tables.getcolumn(r::Row, i::Int) Tables.getcolumn(r, getquery(r).types[i], i, getquery(r).names[i]) end +# non-strict values don't depend on the column type; skip dispatching on it +Tables.getcolumn(r::Row{false}, i::Int) = getvalue(getquery(r), i, getfield(r, :rownumber), Any) function Tables.getcolumn(r::Row, nm::Symbol) Tables.getcolumn(r, getquery(r).lookup[nm]) end diff --git a/test/runtests.jl b/test/runtests.jl index 5b31a2d..5205218 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1126,6 +1126,21 @@ end end end + @testset "Non-strict values follow each value's storage class" begin + db = SQLite.DB() + DBInterface.execute(db, "CREATE TABLE mixed (x INTEGER)") + for v in (1, 1.5, "abc", :sym, UInt8[0x01, 0x02], missing) + DBInterface.execute(db, "INSERT INTO mixed VALUES (?)", (v,)) + end + expected = [1, 1.5, "abc", :sym, UInt8[0x01, 0x02], missing] + @test isequal([row.x for row in DBInterface.execute(db, "SELECT x FROM mixed")], expected) + @test isequal(columntable(DBInterface.execute(db, "SELECT x FROM mixed")).x, expected) + # strict rows read through each column's inferred type + row = first(DBInterface.execute(DBInterface.prepare(db, "SELECT 1 AS i, 1.5 AS f"), (); strict = true)) + @test row.i === 1 && row.f === 1.5 + close(db) + end + @testset "strict mode" begin @testset "Issue #353: ALTER TABLE on a STRICT table" begin for strict in (false, true)