Commit d630b5d88bc for nodejs

commit d630b5d88bc19c10443b3d83b723b7b052fa0c7f
Author: Lazizbek Ergashev <lazerg2@gmail.com>
Date:   Mon Oct 26 04:33:24 2026 +0500

    sqlite: retry busy or locked backup steps

    Signed-off-by: lazerg <lazerg2@gmail.com>
    PR-URL: https://github.com/nodejs/node/pull/66769
    Fixes: https://github.com/nodejs/node/issues/66760
    Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>

diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc
index b8b1988c50b..c8ebd65f5b4 100644
--- a/src/node_sqlite.cc
+++ b/src/node_sqlite.cc
@@ -680,6 +680,11 @@ class BackupJob : public ThreadPoolWork {
       return;
     }

+    if (backup_status_ == SQLITE_BUSY || backup_status_ == SQLITE_LOCKED) {
+      this->ScheduleWork();
+      return;
+    }
+
     int total_pages = sqlite3_backup_pagecount(backup_.get());
     int remaining_pages = sqlite3_backup_remaining(backup_.get());
     if (remaining_pages != 0) {
diff --git a/test/parallel/test-sqlite-backup.mjs b/test/parallel/test-sqlite-backup.mjs
index 633c7da7735..d3d6a433993 100644
--- a/test/parallel/test-sqlite-backup.mjs
+++ b/test/parallel/test-sqlite-backup.mjs
@@ -1,6 +1,7 @@
 // Flags: --expose-gc
 import {
   isWindows,
+  platformTimeout,
   skipIfSQLiteMissing,
   spawnPromisified,
 } from '../common/index.mjs';
@@ -351,6 +352,32 @@ test('backup fails when path cannot be opened', async (t) => {
   });
 });

+test('backup waits for a write transaction on the source to end', async (t) => {
+  const database = makeSourceDb();
+  const destDb = nextDb();
+
+  t.after(() => { database.close(); });
+
+  database.exec('BEGIN IMMEDIATE');
+  database.exec("INSERT INTO data (key, value) VALUES (3, 'value-3')");
+  const p = backup(database, destDb);
+  setTimeout(() => database.exec('COMMIT'), platformTimeout(100));
+
+  await p;
+
+  const backupDb = new Database(destDb);
+
+  t.after(() => { backupDb.close(); });
+
+  const rows = backupDb.prepare('SELECT * FROM data').all();
+
+  t.assert.deepStrictEqual(rows, [
+    { __proto__: null, key: 1, value: 'value-1' },
+    { __proto__: null, key: 2, value: 'value-2' },
+    { __proto__: null, key: 3, value: 'value-3' },
+  ]);
+});
+
 test('backup has correct name and length', (t) => {
   t.assert.strictEqual(backup.name, 'backup');
   t.assert.strictEqual(backup.length, 2);