diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc index 049fd786126fce..c3b7d279f4dca0 100644 --- a/src/node_sqlite.cc +++ b/src/node_sqlite.cc @@ -2865,12 +2865,16 @@ MaybeLocal StatementExecutionHelper::All(Environment* env, Isolate* isolate = env->isolate(); EscapableHandleScope scope(isolate); int r; - int num_cols = sqlite3_column_count(stmt); + int num_cols = 0; LocalVector rows(isolate); LocalVector row_values(isolate); LocalVector row_keys(isolate); while ((r = sqlite3_step(stmt)) == SQLITE_ROW) { + if (num_cols == 0) { + num_cols = sqlite3_column_count(stmt); + } + if (ExtractRowValues(env, stmt, num_cols, use_big_ints, &row_values) .IsNothing()) { return MaybeLocal(); diff --git a/test/parallel/test-sqlite-statement-sync.js b/test/parallel/test-sqlite-statement-sync.js index aa7a3a73ae6649..b3a1dc434537c3 100644 --- a/test/parallel/test-sqlite-statement-sync.js +++ b/test/parallel/test-sqlite-statement-sync.js @@ -53,6 +53,29 @@ suite('StatementSync.prototype.get()', () => { const stmt = db.prepare('SELECT 1 as __proto__, 2 as constructor, 3 as toString'); t.assert.deepStrictEqual(stmt.get(), { __proto__: null, ['__proto__']: 1, constructor: 2, toString: 3 }); }); + + test('reflects an added column after the schema changes', (t) => { + using db = new DatabaseSync(':memory:'); + db.exec('CREATE TABLE storage(key TEXT, val TEXT)'); + db.prepare('INSERT INTO storage (key, val) VALUES (?, ?)').run('key1', 'val1'); + const stmt = db.prepare('SELECT * FROM storage ORDER BY key'); + db.exec("ALTER TABLE storage ADD COLUMN extra TEXT DEFAULT 'def'"); + t.assert.deepStrictEqual(stmt.get(), { + __proto__: null, key: 'key1', val: 'val1', extra: 'def', + }); + }); + + test('reflects a dropped column after the schema changes', (t) => { + using db = new DatabaseSync(':memory:'); + db.exec('CREATE TABLE storage(key TEXT, val TEXT, extra TEXT)'); + db.prepare('INSERT INTO storage (key, val, extra) VALUES (?, ?, ?)') + .run('key1', 'val1', 'x'); + const stmt = db.prepare('SELECT * FROM storage ORDER BY key'); + db.exec('ALTER TABLE storage DROP COLUMN extra'); + t.assert.deepStrictEqual(stmt.get(), { + __proto__: null, key: 'key1', val: 'val1', + }); + }); }); suite('StatementSync.prototype.all()', () => { @@ -83,6 +106,29 @@ suite('StatementSync.prototype.all()', () => { { __proto__: null, key: 'key2', val: 'val2' }, ]); }); + + test('reflects an added column after the schema changes', (t) => { + using db = new DatabaseSync(':memory:'); + db.exec('CREATE TABLE storage(key TEXT, val TEXT)'); + db.prepare('INSERT INTO storage (key, val) VALUES (?, ?)').run('key1', 'val1'); + const stmt = db.prepare('SELECT * FROM storage ORDER BY key'); + db.exec("ALTER TABLE storage ADD COLUMN extra TEXT DEFAULT 'def'"); + t.assert.deepStrictEqual(stmt.all(), [ + { __proto__: null, key: 'key1', val: 'val1', extra: 'def' }, + ]); + }); + + test('reflects a dropped column after the schema changes', (t) => { + using db = new DatabaseSync(':memory:'); + db.exec('CREATE TABLE storage(key TEXT, val TEXT, extra TEXT)'); + db.prepare('INSERT INTO storage (key, val, extra) VALUES (?, ?, ?)') + .run('key1', 'val1', 'x'); + const stmt = db.prepare('SELECT * FROM storage ORDER BY key'); + db.exec('ALTER TABLE storage DROP COLUMN extra'); + t.assert.deepStrictEqual(stmt.all(), [ + { __proto__: null, key: 'key1', val: 'val1' }, + ]); + }); }); suite('StatementSync.prototype.iterate()', () => { @@ -125,6 +171,29 @@ suite('StatementSync.prototype.iterate()', () => { } }); + test('reflects an added column after the schema changes', (t) => { + using db = new DatabaseSync(':memory:'); + db.exec('CREATE TABLE storage(key TEXT, val TEXT)'); + db.prepare('INSERT INTO storage (key, val) VALUES (?, ?)').run('key1', 'val1'); + const stmt = db.prepare('SELECT * FROM storage ORDER BY key'); + db.exec("ALTER TABLE storage ADD COLUMN extra TEXT DEFAULT 'def'"); + t.assert.deepStrictEqual(stmt.iterate().toArray(), [ + { __proto__: null, key: 'key1', val: 'val1', extra: 'def' }, + ]); + }); + + test('reflects a dropped column after the schema changes', (t) => { + using db = new DatabaseSync(':memory:'); + db.exec('CREATE TABLE storage(key TEXT, val TEXT, extra TEXT)'); + db.prepare('INSERT INTO storage (key, val, extra) VALUES (?, ?, ?)') + .run('key1', 'val1', 'x'); + const stmt = db.prepare('SELECT * FROM storage ORDER BY key'); + db.exec('ALTER TABLE storage DROP COLUMN extra'); + t.assert.deepStrictEqual(stmt.iterate().toArray(), [ + { __proto__: null, key: 'key1', val: 'val1' }, + ]); + }); + test('iterator keeps the prepared statement from being collected', (t) => { const db = new DatabaseSync(':memory:'); db.exec(`