sqlite: reset statement immediately in run()

This commit updates StatementSync.prototype.run() to reset the
prepared statement immediately after calling sqlite3_step() to
return the correct change metadata.

Fixes: https://github.com/nodejs/node/issues/57344
PR-URL: https://github.com/nodejs/node/pull/57350
Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
Reviewed-By: Jake Yuesong Li <jake.yuesong@gmail.com>
This commit is contained in:
Colin Ihrig 2025-03-10 20:33:27 -04:00 committed by Michaël Zasso
parent b866755299
commit 21b6423b9b
No known key found for this signature in database
GPG Key ID: 770F7A9A5AE15600
2 changed files with 22 additions and 7 deletions

View File

@ -1866,13 +1866,9 @@ void StatementSync::Run(const FunctionCallbackInfo<Value>& args) {
return;
}
auto reset = OnScopeLeave([&]() { sqlite3_reset(stmt->statement_); });
r = sqlite3_step(stmt->statement_);
if (r != SQLITE_ROW && r != SQLITE_DONE) {
THROW_ERR_SQLITE_ERROR(env->isolate(), stmt->db_.get());
return;
}
sqlite3_step(stmt->statement_);
r = sqlite3_reset(stmt->statement_);
CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
Local<Object> result = Object::New(env->isolate());
sqlite3_int64 last_insert_rowid =
sqlite3_last_insert_rowid(stmt->db_->Connection());

View File

@ -170,6 +170,25 @@ suite('StatementSync.prototype.run()', () => {
errstr: 'constraint failed',
});
});
test('returns correct metadata when using RETURNING', (t) => {
const db = new DatabaseSync(':memory:');
const setup = db.exec(
'CREATE TABLE data(key INTEGER PRIMARY KEY, val INTEGER NOT NULL) STRICT;'
);
t.assert.strictEqual(setup, undefined);
const sql = 'INSERT INTO data (key, val) VALUES ($k, $v) RETURNING key';
const stmt = db.prepare(sql);
t.assert.deepStrictEqual(
stmt.run({ k: 1, v: 10 }), { changes: 1, lastInsertRowid: 1 }
);
t.assert.deepStrictEqual(
stmt.run({ k: 2, v: 20 }), { changes: 1, lastInsertRowid: 2 }
);
t.assert.deepStrictEqual(
stmt.run({ k: 3, v: 30 }), { changes: 1, lastInsertRowid: 3 }
);
});
});
suite('StatementSync.prototype.sourceSQL', () => {