diff --git a/src/tables.jl b/src/tables.jl index 8e2ae27..707cb22 100644 --- a/src/tables.jl +++ b/src/tables.jl @@ -175,14 +175,15 @@ tableinfo(db::DB, name::AbstractString) = end """ - source |> SQLite.load!(db::SQLite.DB, tablename::String; temp::Bool=false, ifnotexists::Bool=false, analyze::Bool=false) - SQLite.load!(source, db, tablename; temp=false, ifnotexists=false, analyze::Bool=false) + source |> SQLite.load!(db::SQLite.DB, tablename::String; temp::Bool=false, ifnotexists::Bool=false, replace::Bool=false, analyze::Bool=false) + SQLite.load!(source, db, tablename; temp=false, ifnotexists=false, replace::Bool=false, analyze::Bool=false) Load a Tables.jl input `source` into an SQLite table that will be named `tablename` (will be auto-generated if not specified). -`temp=true` will create a temporary SQLite table that will be destroyed automatically when the database is closed -`ifnotexists=false` will throw an error if `tablename` already exists in `db` -`analyze=true` will execute `ANALYZE` at the end of the insert + * `temp=true` will create a temporary SQLite table that will be destroyed automatically when the database is closed + * `ifnotexists=false` will throw an error if `tablename` already exists in `db` + * `replace=false` controls whether an `INSERT INTO ...` statement is generated or a `REPLACE INTO ...` + * `analyze=true` will execute `ANALYZE` at the end of the insert """ function load! end @@ -222,7 +223,7 @@ function checknames(::Tables.Schema{names}, db_names::AbstractVector{String}) wh end function load!(sch::Tables.Schema, rows, db::DB, name::AbstractString, db_tableinfo::Union{NamedTuple, Nothing}, row=nothing, st=nothing; - temp::Bool=false, ifnotexists::Bool=false, analyze::Bool=false) + temp::Bool=false, ifnotexists::Bool=false, replace::Bool=false, analyze::Bool=false) # check for case-insensitive duplicate column names (sqlite doesn't allow) checkdupnames(sch.names) # check if `rows` column names match the existing table, or create the new one @@ -234,7 +235,8 @@ function load!(sch::Tables.Schema, rows, db::DB, name::AbstractString, db_tablei # build insert statement columns = join(esc_id.(string.(sch.names)), ",") params = chop(repeat("?,", length(sch.names))) - stmt = _Stmt(db, "INSERT INTO $(esc_id(string(name))) ($columns) VALUES ($params)") + kind = replace ? "REPLACE" : "INSERT" + stmt = _Stmt(db, "$kind INTO $(esc_id(string(name))) ($columns) VALUES ($params)") # start a transaction for inserting rows transaction(db) do if row === nothing @@ -246,8 +248,14 @@ function load!(sch::Tables.Schema, rows, db::DB, name::AbstractString, db_tablei Tables.eachcolumn(sch, row) do val, col, _ bind!(stmt, col, val) end - sqlite3_step(stmt.handle) - sqlite3_reset(stmt.handle) + r = sqlite3_step(stmt.handle) + if r == SQLITE_DONE + sqlite3_reset(stmt.handle) + elseif r != SQLITE_ROW + e = sqliteexception(db) + sqlite3_reset(stmt.handle) + throw(e) + end state = iterate(rows, st) state === nothing && break row, st = state diff --git a/test/runtests.jl b/test/runtests.jl index 72c753b..f815e5f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -526,7 +526,7 @@ end Tables.isrowtable(::Type{UnknownSchemaTable}) = true Tables.rows(x::UnknownSchemaTable) = x Base.length(x::UnknownSchemaTable) = 3 -Base.iterate(::UnknownSchemaTable, st=1) = st == 4 ? nothing : ((a=1, b=2, c=3), st + 1) +Base.iterate(::UnknownSchemaTable, st=1) = st == 4 ? nothing : ((a=1, b=2 + st, c=3 + st), st + 1) @testset "misc" begin @@ -536,15 +536,27 @@ SQLite.load!(UnknownSchemaTable(), db, "tbl") tbl = DBInterface.execute(db, "select * from tbl") |> columntable @test tbl == ( a = [1, 1, 1], - b = [2, 2, 2], - c = [3, 3, 3] + b = [3, 4, 5], + c = [4, 5, 6] ) # https://github.com/JuliaDatabases/SQLite.jl/issues/251 q = DBInterface.execute(db, "select * from tbl") row, st = iterate(q) -@test row.a == 1 && row.b == 2 && row.c == 3 +@test row.a == 1 && row.b == 3 && row.c == 4 row2, st = iterate(q, st) @test_throws ArgumentError row.a +# https://github.com/JuliaDatabases/SQLite.jl/issues/243 +db = SQLite.DB() +DBInterface.execute(db, "create table tmp ( a INTEGER NOT NULL PRIMARY KEY, b INTEGER, c INTEGER )") +@test_throws SQLite.SQLiteException SQLite.load!(UnknownSchemaTable(), db, "tmp") +SQLite.load!(UnknownSchemaTable(), db, "tmp"; replace=true) +tbl = DBInterface.execute(db, "select * from tmp") |> columntable +@test tbl == ( + a = [1], + b = [5], + c = [6] +) + end \ No newline at end of file