Skip to content

Commit dd14546

Browse files
quinnjbkamins
andauthored
By default, make query column names unique (#254)
* By default, make query column names unique Fixes #253. Most data formats have requirements around column name uniqueness, including DataFrames.jl. The proposed changes here ensure query result columns are unique by default, while still allowing column names to be duplicated if they pass `allowduplicates=true` to `DBInterface.execute`. * Update test/runtests.jl Co-authored-by: Bogumił Kamiński <[email protected]> Co-authored-by: Bogumił Kamiński <[email protected]>
1 parent 466e080 commit dd14546

File tree

3 files changed

+19
-4
lines changed

3 files changed

+19
-4
lines changed

src/SQLite.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ end
458458
execute(stmt::Stmt, params::DBInterface.StatementParams) =
459459
execute(stmt.db, _stmt(stmt), params)
460460

461-
execute(stmt::Stmt; kwargs...) = execute(stmt, kwargs.data)
461+
execute(stmt::Stmt; kwargs...) = execute(stmt, values(kwargs))
462462

463463
function execute(db::DB, sql::AbstractString, params::DBInterface.StatementParams)
464464
# prepare without registering _Stmt in DB
@@ -470,7 +470,7 @@ function execute(db::DB, sql::AbstractString, params::DBInterface.StatementParam
470470
end
471471
end
472472

473-
execute(db::DB, sql::AbstractString; kwargs...) = execute(db, sql, kwargs.data)
473+
execute(db::DB, sql::AbstractString; kwargs...) = execute(db, sql, values(kwargs))
474474

475475
"""
476476
SQLite.esc_id(x::Union{AbstractString,Vector{AbstractString}})

src/tables.jl

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,24 @@ Calling `SQLite.reset!(result)` will re-execute the query and reset the iterator
109109
The resultset iterator supports the [Tables.jl](https://github.com/JuliaData/Tables.jl) interface, so results can be collected in any Tables.jl-compatible sink,
110110
like `DataFrame(results)`, `CSV.write("results.csv", results)`, etc.
111111
"""
112-
function DBInterface.execute(stmt::Stmt, params::DBInterface.StatementParams)
112+
function DBInterface.execute(stmt::Stmt, params::DBInterface.StatementParams; allowduplicates::Bool=false)
113113
status = execute(stmt, params)
114114
_st = _stmt(stmt)
115115
cols = sqlite3_column_count(_st.handle)
116116
header = Vector{Symbol}(undef, cols)
117117
types = Vector{Type}(undef, cols)
118118
for i = 1:cols
119-
header[i] = sym(sqlite3_column_name(_st.handle, i))
119+
nm = sym(sqlite3_column_name(_st.handle, i))
120+
if !allowduplicates && nm in view(header, 1:(i - 1))
121+
j = 1
122+
newnm = Symbol(nm, :_, j)
123+
while newnm in view(header, 1:(i - 1))
124+
j += 1
125+
newnm = Symbol(nm, :_, j)
126+
end
127+
nm = newnm
128+
end
129+
header[i] = nm
120130
types[i] = Union{juliatype(_st.handle, i), Missing}
121131
end
122132
return Query(stmt, Ref(status), header, types, Dict(x=>i for (i, x) in enumerate(header)))

test/runtests.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,11 @@ tbl3 = (c = [7, 8, 9], a = [4, 5, 6])
424424
# Test busy_timeout
425425
@test SQLite.busy_timeout(db, 300) == 0
426426

427+
# 253, ensure query column names are unique by default
428+
db = SQLite.DB()
429+
res = DBInterface.execute(db, "select 1 as x2, 2 as x2, 3 as x2, 4 as x2_2") |> columntable
430+
@test res == (x2 = [1], x2_1 = [2], x2_2 = [3], x2_2_1 = [4])
431+
427432
@testset "load!()/drop!() table name escaping" begin
428433
tbl = (a = [1, 2, 3], b = ["a", "b", "c"])
429434
SQLite.load!(tbl, db, "escape 10.0%")

0 commit comments

Comments
 (0)