Commit 1c38c9196fa for nodejs
commit 1c38c9196faf9845d390a9c7bfcc799c6d64cc74
Author: Guilherme Araújo <arauujogui@gmail.com>
Date: Tue Oct 20 22:51:22 2026 -0300
sqlite: use DeleteFnPtr for all SQLite handles
Replace the custom deleter structs and OnScopeLeave cleanups with
DeleteFnPtr aliases, and pass session ownership to Session::Create.
Signed-off-by: Guilherme Araújo <arauujogui@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66912
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc
index 07979acd3df..b10044a7b15 100644
--- a/src/node_sqlite.cc
+++ b/src/node_sqlite.cc
@@ -743,9 +743,7 @@ class BackupJob : public ThreadPoolWork {
}
void Cleanup() {
- if (backup_) {
- sqlite3_backup_finish(backup_.release());
- }
+ backup_.reset();
if (dest_) {
backup_status_ = sqlite3_errcode(dest_.get());
@@ -786,14 +784,8 @@ class BackupJob : public ThreadPoolWork {
BaseObjectPtr<Database> source_;
Global<Promise::Resolver> resolver_;
Global<Function> progressFunc_;
- struct Sqlite3Deleter {
- void operator()(sqlite3* db) const { sqlite3_close_v2(db); }
- };
- struct BackupDeleter {
- void operator()(sqlite3_backup* b) const { sqlite3_backup_finish(b); }
- };
- std::unique_ptr<sqlite3, Sqlite3Deleter> dest_;
- std::unique_ptr<sqlite3_backup, BackupDeleter> backup_;
+ ConnectionPtr dest_;
+ BackupPtr backup_;
int pages_;
int backup_status_ = SQLITE_OK;
std::string source_db_;
@@ -2101,6 +2093,8 @@ void Database::Close(const FunctionCallbackInfo<Value>& args) {
env, db->IsInCallback(), "database cannot be closed while in a callback");
db->FinalizeStatements();
db->DeleteSessions();
+ // Close through the raw handle instead of reset() so that a failed close
+ // keeps the handle, which the error below is read from.
int r = sqlite3_close_v2(db->connection_.get());
CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
db->connection_.release();
@@ -2892,26 +2886,21 @@ void Database::CreateSession(const FunctionCallbackInfo<Value>& args) {
// getter, which may have closed the database since it was checked.
THROW_AND_RETURN_ON_BAD_STATE(env, !db->IsOpen(), "database is not open");
- sqlite3_session* pSession;
- int r =
- sqlite3session_create(db->connection_.get(), db_name.c_str(), &pSession);
+ sqlite3_session* raw_session;
+ int r = sqlite3session_create(
+ db->connection_.get(), db_name.c_str(), &raw_session);
CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
- bool wrapper_owns_session = false;
- auto delete_session_on_failure = OnScopeLeave([&]() {
- if (!wrapper_owns_session) {
- sqlite3session_delete(pSession);
- }
- });
+ SessionPtr pSession(raw_session);
- r = sqlite3session_attach(pSession, table == "" ? nullptr : table.c_str());
+ r = sqlite3session_attach(pSession.get(),
+ table == "" ? nullptr : table.c_str());
CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void());
BaseObjectPtr<Session> session =
- Session::Create(env, BaseObjectPtr<Database>(db), pSession);
+ Session::Create(env, BaseObjectPtr<Database>(db), std::move(pSession));
if (!session) {
return;
}
- wrapper_owns_session = true;
args.GetReturnValue().Set(session->object());
}
@@ -4898,9 +4887,9 @@ void StatementIterator::Return(const FunctionCallbackInfo<Value>& args) {
Session::Session(Environment* env,
Local<Object> object,
BaseObjectPtr<Database> database,
- sqlite3_session* session)
+ SessionPtr session)
: BaseObject(env, object),
- session_(std::unique_ptr<sqlite3_session, SessionDeleter>(session)),
+ session_(std::move(session)),
database_(std::move(database)) {
database_->sessions_.insert(this);
MakeWeak();
@@ -4912,7 +4901,7 @@ Session::~Session() {
BaseObjectPtr<Session> Session::Create(Environment* env,
BaseObjectPtr<Database> database,
- sqlite3_session* session) {
+ SessionPtr session) {
Local<Object> obj;
if (!GetConstructorTemplate(env)
->InstanceTemplate()
@@ -4921,7 +4910,8 @@ BaseObjectPtr<Session> Session::Create(Environment* env,
return nullptr;
}
- return MakeBaseObject<Session>(env, obj, std::move(database), session);
+ return MakeBaseObject<Session>(
+ env, obj, std::move(database), std::move(session));
}
Local<FunctionTemplate> Session::GetConstructorTemplate(Environment* env) {
@@ -4970,7 +4960,7 @@ void Session::Changeset(const FunctionCallbackInfo<Value>& args) {
CHECK_ERROR_OR_THROW(
env->isolate(), session->database_.get(), r, SQLITE_OK, void());
- auto freeChangeset = OnScopeLeave([&] { sqlite3_free(pChangeset); });
+ DeleteFnPtr<void, sqlite3_free> changeset(pChangeset);
Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), nChangeset);
if (nChangeset > 0) {
diff --git a/src/node_sqlite.h b/src/node_sqlite.h
index 2adb95f62dd..2bba70c3bba 100644
--- a/src/node_sqlite.h
+++ b/src/node_sqlite.h
@@ -173,7 +173,18 @@ inline void FinalizeStatement(sqlite3_stmt* stmt) {
sqlite3_finalize(stmt);
}
+inline void CloseConnection(sqlite3* db) {
+ sqlite3_close_v2(db);
+}
+
+inline void FinishBackup(sqlite3_backup* backup) {
+ sqlite3_backup_finish(backup);
+}
+
using StatementPtr = DeleteFnPtr<sqlite3_stmt, FinalizeStatement>;
+using ConnectionPtr = DeleteFnPtr<sqlite3, CloseConnection>;
+using BackupPtr = DeleteFnPtr<sqlite3_backup, FinishBackup>;
+using SessionPtr = DeleteFnPtr<sqlite3_session, sqlite3session_delete>;
class StatementExecutionHelper {
public:
@@ -338,10 +349,7 @@ class Database : public BaseObject {
DatabaseOpenConfiguration open_config_;
bool allow_load_extension_;
bool enable_load_extension_;
- struct ConnectionDeleter {
- void operator()(sqlite3* db) const { sqlite3_close_v2(db); }
- };
- std::unique_ptr<sqlite3, ConnectionDeleter> connection_;
+ ConnectionPtr connection_;
bool ignore_next_sqlite_error_;
int callback_depth_ = 0;
int destructor_depth_ = 0;
@@ -465,7 +473,7 @@ class Session : public BaseObject {
Session(Environment* env,
v8::Local<v8::Object> object,
BaseObjectPtr<Database> database,
- sqlite3_session* session);
+ SessionPtr session);
~Session() override;
template <Sqlite3ChangesetGenFunc sqliteChangesetFunc>
static void Changeset(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -475,7 +483,7 @@ class Session : public BaseObject {
Environment* env);
static BaseObjectPtr<Session> Create(Environment* env,
BaseObjectPtr<Database> database,
- sqlite3_session* session);
+ SessionPtr session);
void MemoryInfo(MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(Session)
@@ -483,10 +491,7 @@ class Session : public BaseObject {
private:
void Delete();
- struct SessionDeleter {
- void operator()(sqlite3_session* s) const { sqlite3session_delete(s); }
- };
- std::unique_ptr<sqlite3_session, SessionDeleter> session_;
+ SessionPtr session_;
BaseObjectPtr<Database> database_; // The Parent Database
bool is_generating_changeset_ = false;