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;