From d666b946aa87c351ad57040bf0f707d201f8bca8 Mon Sep 17 00:00:00 2001 From: "Kamat, Trivikram" <16024985+trivikr@users.noreply.github.com> Date: Fri, 31 Jul 2026 20:00:16 -0700 Subject: [PATCH] sqlite: reject non-positive backup rates Passing a rate of 0 to backup() causes sqlite3_backup_step() to copy no pages. The backup job then continually reschedules itself and the returned promise never settles. Require backup rates to be positive integers to prevent zero-work backup jobs. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: codex:gpt-5.6-sol --- doc/api/sqlite.md | 2 +- src/node_sqlite.cc | 6 ++++++ test/parallel/test-sqlite-backup.mjs | 9 +++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/doc/api/sqlite.md b/doc/api/sqlite.md index 850358ff43aa..d45024a5cb0b 100644 --- a/doc/api/sqlite.md +++ b/doc/api/sqlite.md @@ -1356,7 +1356,7 @@ changes: database that have been added with [`ATTACH DATABASE`][] **Default:** `'main'`. * `target` {string} Name of the target database. This can be `'main'` (the default primary database) or any other database that have been added with [`ATTACH DATABASE`][] **Default:** `'main'`. - * `rate` {number} Number of pages to be transmitted in each batch of the backup. **Default:** `100`. + * `rate` {integer} Positive number of pages to be transmitted in each batch of the backup. **Default:** `100`. * `progress` {Function} An optional callback function that will be called after each backup step. The argument passed to this callback is an {Object} with `remainingPages` and `totalPages` properties, describing the current progress of the backup operation. diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc index 8c3709178af0..cd37ff2f15a5 100644 --- a/src/node_sqlite.cc +++ b/src/node_sqlite.cc @@ -2171,6 +2171,12 @@ void Backup(const FunctionCallbackInfo& args) { return; } rate = rate_v.As()->Value(); + if (rate <= 0) { + THROW_ERR_OUT_OF_RANGE( + env->isolate(), + "The \"options.rate\" argument must be a positive integer."); + return; + } } Local source_v; diff --git a/test/parallel/test-sqlite-backup.mjs b/test/parallel/test-sqlite-backup.mjs index 80061ee6601d..d1e09569e1ca 100644 --- a/test/parallel/test-sqlite-backup.mjs +++ b/test/parallel/test-sqlite-backup.mjs @@ -124,6 +124,15 @@ describe('backup()', () => { message: 'The "options.rate" argument must be an integer.' }); + for (const rate of [0, -1]) { + t.assert.throws(() => { + backup(database, 'hello.db', { rate }); + }, { + code: 'ERR_OUT_OF_RANGE', + message: 'The "options.rate" argument must be a positive integer.' + }); + } + t.assert.throws(() => { backup(database, 'hello.db', { progress: 'invalid'