current commit
260926.1 · sqlite: rename DatabaseSync and StatementSync
'use strict';

const { skipIfSQLiteMissing, mustCall } = require('../common');
skipIfSQLiteMissing();
const assert = require('node:assert');
const { test } = require('node:test');
const { Database } = require('node:sqlite');

const reentryError = {
  code: 'ERR_INVALID_STATE',
  message: 'statement is already being executed',
};

// Binding a named parameter reads properties off the supplied object, so a
// getter runs JavaScript after the statement has been reset but before it is
// stepped. Reentering the same statement there resets it a second time and
// hands out a second iterator over one virtual machine.
for (const method of ['all', 'get', 'run', 'iterate']) {
  test(`${method}() reentry during parameter binding is rejected`, () => {
    const db = new Database(':memory:');
    db.exec(`
      CREATE TABLE data (value INTEGER);
      INSERT INTO data VALUES (1), (2), (3);
    `);

    let statement;
    const invoke = (params) => (method === 'iterate' ?
      [...statement.iterate(params)] :
      statement[method](params));
    const reenter = mustCall(() => {
      assert.throws(() => invoke({ $min: 2 }), reentryError);
      return 1;
    });
    const params = { get $min() { return reenter(); } };

    statement = db.prepare('SELECT value FROM data WHERE value >= $min');
    invoke(params);
  });
}

test('two iterators cannot share one virtual machine', () => {
  const db = new Database(':memory:');
  db.exec(`
    CREATE TABLE data (value INTEGER);
    INSERT INTO data VALUES (1), (2), (3);
  `);

  const statement = db.prepare('SELECT value FROM data WHERE value >= $min');
  let inner;
  const reenter = mustCall(() => {
    assert.throws(() => {
      inner = statement.iterate({ $min: 1 });
    }, reentryError);
    return 1;
  });
  const params = { get $min() { return reenter(); } };

  assert.deepStrictEqual(
    [...statement.iterate(params)].map((row) => row.value),
    [1, 2, 3],
  );
  assert.strictEqual(inner, undefined);
});