Skip to content

Commit 0517515

Browse files
authored
Report the failing INSERT when load!() errors (#277)
SQLite3 provides `sqlite3_expanded_sql()` to retrieve the _as-bound_ statement text; this makes it possible to report the exact failing INSERT when `load!()` fails, e.g. due to a `PRIMARY KEY` violation.
1 parent f9c7d62 commit 0517515

File tree

3 files changed

+19
-1
lines changed

3 files changed

+19
-1
lines changed

src/SQLite.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,17 @@ const StmtHandle = Ptr{Cvoid} # SQLite3 prepared statement handle
1717

1818
# Normal constructor from filename
1919
sqliteexception(handle::DBHandle) = SQLiteException(unsafe_string(sqlite3_errmsg(handle)))
20+
function sqliteexception(handle::DBHandle, stmt::StmtHandle)
21+
errstr = unsafe_string(sqlite3_errmsg(handle))
22+
stmt_text_handle = sqlite3_expanded_sql(stmt)
23+
stmt_text = unsafe_string(stmt_text_handle)
24+
msg = "$errstr on statement \"$stmt_text\""
25+
sqlite3_free(convert(Ptr{Cvoid}, stmt_text_handle))
26+
return SQLiteException(msg)
27+
end
28+
2029
sqliteerror(handle::DBHandle) = throw(sqliteexception(handle))
30+
sqliteerror(handle::DBHandle, stmt::StmtHandle) = throw(sqliteexception(handle, stmt))
2131

2232
"""
2333
Internal wrapper that holds the handle to SQLite3 prepared statement.
@@ -158,6 +168,8 @@ mutable struct Stmt <: DBInterface.Statement
158168
end
159169
end
160170

171+
sqliteexception(db::DB, stmt::_Stmt) = sqliteexception(db.handle, stmt.handle)
172+
161173
# check if the statement is ready (not finalized due to
162174
# _close(_Stmt) called and the statment handle removed from DB)
163175
isready(stmt::Stmt) = haskey(stmt.db.stmts, stmt.id)

src/api.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ function sqlite3_prepare16_v2(handle::Ptr{Cvoid}, query::AbstractString, stmt, u
3838
Cint, (Ptr{Cvoid}, Ptr{UInt16}, Cint, Ptr{Cvoid}, Ptr{Cvoid}),
3939
handle, query, sizeof(query), stmt, unused)
4040
end
41+
function sqlite3_expanded_sql(stmt::Ptr{Cvoid})
42+
@NULLCHECK stmt
43+
return ccall( (:sqlite3_expanded_sql, libsqlite),
44+
Ptr{UInt8}, (Ptr{Cvoid},), stmt)
45+
end
46+
sqlite3_free(ptr::Ptr{Cvoid}) = ccall( (:sqlite3_free, libsqlite), Cvoid, (Ptr{Cvoid},), ptr)
4147
function sqlite3_finalize(stmt::Ptr{Cvoid})
4248
@NULLCHECK stmt
4349
return ccall( (:sqlite3_finalize, libsqlite),

src/tables.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ function load!(sch::Tables.Schema, rows, db::DB, name::AbstractString, db_tablei
252252
if r == SQLITE_DONE
253253
sqlite3_reset(stmt.handle)
254254
elseif r != SQLITE_ROW
255-
e = sqliteexception(db)
255+
e = sqliteexception(db, stmt)
256256
sqlite3_reset(stmt.handle)
257257
throw(e)
258258
end

0 commit comments

Comments
 (0)