1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-27 20:41:58 +03:00

sqlite3.oo1.Stmt.finalize() now throws if sqlite3_finalize() returns non-zero. This is intended to address the INSERT RETURNING case covered in [forum:36f7a2e7494897df|forum post 36f7a2e7494897df].

FossilOrigin-Name: f23eb5c6d36546ee1e181a03660e0b2dc8005bba24bee8bae594b0c78bd152cd
This commit is contained in:
stephan
2023-05-19 15:54:41 +00:00
parent 8e2fd6eae3
commit 2492b6c0fb
5 changed files with 40 additions and 19 deletions

View File

@ -55,6 +55,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if(sqliteResultCode){
if(dbPtr instanceof DB) dbPtr = dbPtr.pointer;
toss3(
sqliteResultCode,
"sqlite3 result code",sqliteResultCode+":",
(dbPtr
? capi.sqlite3_errmsg(dbPtr)
@ -503,6 +504,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
"Not an error." The various non-0 non-error codes need to be
checked for in client code where they are expected.
The thrown exception's `resultCode` property will be the value of
the second argument to this function.
If it does not throw, it returns its first argument.
*/
DB.checkRc = (db,resultCode)=>checkSqlite3Rc(db,resultCode);
@ -899,11 +903,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
sqlite3.config.warn("DB.exec() is propagating exception",opt,e);
throw e;
}*/finally{
wasm.scopedAllocPop(stack);
if(stmt){
delete stmt._isLocked;
stmt.finalize();
}
wasm.scopedAllocPop(stack);
}
return arg.returnVal();
}/*exec()*/,
@ -1256,7 +1260,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
not throw, it returns this object.
*/
checkRc: function(resultCode){
return DB.checkRc(this, resultCode);
return checkSqlite3Rc(this, resultCode);
}
}/*DB.prototype*/;
@ -1420,24 +1424,40 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
Stmt.prototype = {
/**
"Finalizes" this statement. This is a no-op if the
statement has already been finalizes. Returns
statement has already been finalized. Returns
undefined. Most methods in this class will throw if called
after this is.
This method always throws if called when it is illegal to do
so, e.g. from a per-row callback handler of a DB.exec() call.
As of version 3.43, this method will throw if
sqlite3_finalize() returns an error code, which can happen in
certain unusual cases involving locking. When it throws for
this reason, throwing is delayed until after all resources are
cleaned up. That is, the finalization still runs to
completion.
*/
finalize: function(){
if(this.pointer){
affirmUnlocked(this,'finalize()');
delete __stmtMap.get(this.db)[this.pointer];
capi.sqlite3_finalize(this.pointer);
const rc = capi.sqlite3_finalize(this.pointer),
db = this.db;
delete __stmtMap.get(db)[this.pointer];
__ptrMap.delete(this);
delete this._mayGet;
delete this.parameterCount;
delete this.db;
delete this._isLocked;
delete this.db;
checkSqlite3Rc(db, rc);
}
},
/** Clears all bound values. Returns this object.
Throws if this statement has been finalized. */
/**
Clears all bound values. Returns this object. Throws if this
statement has been finalized or if modification of the
statement is currently illegal (e.g. in the per-row callback of
a DB.exec() call).
*/
clearBindings: function(){
affirmUnlocked(affirmStmtOpen(this), 'clearBindings()')
capi.sqlite3_clear_bindings(this.pointer);