diff --git a/src/SQLite.jl b/src/SQLite.jl index d8fb19a..815168f 100644 --- a/src/SQLite.jl +++ b/src/SQLite.jl @@ -458,7 +458,7 @@ end execute(stmt::Stmt, params::DBInterface.StatementParams) = execute(stmt.db, _stmt(stmt), params) -execute(stmt::Stmt; kwargs...) = execute(stmt, kwargs.data) +execute(stmt::Stmt; kwargs...) = execute(stmt, values(kwargs)) function execute(db::DB, sql::AbstractString, params::DBInterface.StatementParams) # prepare without registering _Stmt in DB @@ -470,7 +470,7 @@ function execute(db::DB, sql::AbstractString, params::DBInterface.StatementParam end end -execute(db::DB, sql::AbstractString; kwargs...) = execute(db, sql, kwargs.data) +execute(db::DB, sql::AbstractString; kwargs...) = execute(db, sql, values(kwargs)) """ SQLite.esc_id(x::Union{AbstractString,Vector{AbstractString}}) diff --git a/src/tables.jl b/src/tables.jl index 0592c38..d38ecc8 100644 --- a/src/tables.jl +++ b/src/tables.jl @@ -109,14 +109,24 @@ Calling `SQLite.reset!(result)` will re-execute the query and reset the iterator 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, like `DataFrame(results)`, `CSV.write("results.csv", results)`, etc. """ -function DBInterface.execute(stmt::Stmt, params::DBInterface.StatementParams) +function DBInterface.execute(stmt::Stmt, params::DBInterface.StatementParams; allowduplicates::Bool=false) status = execute(stmt, params) _st = _stmt(stmt) cols = sqlite3_column_count(_st.handle) header = Vector{Symbol}(undef, cols) types = Vector{Type}(undef, cols) for i = 1:cols - header[i] = sym(sqlite3_column_name(_st.handle, i)) + nm = sym(sqlite3_column_name(_st.handle, i)) + if !allowduplicates && nm in view(header, 1:(i - 1)) + j = 1 + newnm = Symbol(nm, :_, j) + while newnm in view(header, 1:(i - 1)) + j += 1 + newnm = Symbol(nm, :_, j) + end + nm = newnm + end + header[i] = nm types[i] = Union{juliatype(_st.handle, i), Missing} end return Query(stmt, Ref(status), header, types, Dict(x=>i for (i, x) in enumerate(header))) diff --git a/test/runtests.jl b/test/runtests.jl index c4782f2..415cc72 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -424,6 +424,11 @@ tbl3 = (c = [7, 8, 9], a = [4, 5, 6]) # Test busy_timeout @test SQLite.busy_timeout(db, 300) == 0 +# 253, ensure query column names are unique by default +db = SQLite.DB() +res = DBInterface.execute(db, "select 1 as x2, 2 as x2, 3 as x2, 4 as x2_2") |> columntable +@test res == (x2 = [1], x2_1 = [2], x2_2 = [3], x2_2_1 = [4]) + @testset "load!()/drop!() table name escaping" begin tbl = (a = [1, 2, 3], b = ["a", "b", "c"]) SQLite.load!(tbl, db, "escape 10.0%")