From d1a6e9c40b254d462f51187d294501139ac12b56 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Aug 2026 11:37:48 +0000 Subject: [PATCH 1/8] Initial plan From c69039a03977139bacb732c6c9a6e5ca62eb28dc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Aug 2026 11:42:39 +0000 Subject: [PATCH 2/8] fix: support async sql.js initialization for sqlite attach --- src/93sqljs.js | 78 ++++++++++++++++++++++++++--------- test/test1284.js | 103 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 19 deletions(-) create mode 100644 test/test1284.js diff --git a/src/93sqljs.js b/src/93sqljs.js index 294082168d..af18811714 100755 --- a/src/93sqljs.js +++ b/src/93sqljs.js @@ -6,6 +6,44 @@ var SQLITE = (alasql.engines.SQLITE = function () {}); +function getSqlJs(cb) { + var sqljs = SQLITE.sqljs; + var sqljsPromise = SQLITE.sqljsPromise; + + if (sqljs && sqljs.Database) { + cb(sqljs); + return; + } + + if (typeof SQL !== 'undefined' && SQL && SQL.Database) { + SQLITE.sqljs = sqljs = SQL; + cb(sqljs); + return; + } + + var initSqlJs = + (typeof SQL !== 'undefined' && typeof SQL === 'function' && SQL) || + alasql.utils.global.initSqlJs; + + if (!initSqlJs) { + throw new Error('SQL.js library is not loaded'); + } + + if (!sqljsPromise) { + var initResult = initSqlJs(); + SQLITE.sqljsPromise = sqljsPromise = + initResult && typeof initResult.then === 'function' + ? initResult + : Promise.resolve(initResult); + SQLITE.sqljsPromise = sqljsPromise = sqljsPromise.then(function (SQL) { + SQLITE.sqljs = sqljs = SQL; + return SQL; + }); + } + + sqljsPromise.then(cb); +} + SQLITE.createDatabase = function (wdbid, args, ifnotexists, dbid, cb) { throw new Error('Connot create SQLITE database in memory. Attach it.'); }; @@ -30,26 +68,28 @@ SQLITE.attachDatabase = function (sqldbid, dbid, args, params, cb) { value, true, function (data) { - var db = new alasql.Database(dbid || sqldbid); - db.engineid = 'SQLITE'; - db.sqldbid = sqldbid; - var sqldb = (db.sqldb = new SQL.Database(data)); - db.tables = []; - var tables = sqldb.exec("SELECT * FROM sqlite_master WHERE type='table'")[0].values; - - tables.forEach(function (tbl) { - db.tables[tbl[1]] = {}; - var columns = (db.tables[tbl[1]].columns = []); - var ast = alasql.parse(tbl[4]); - var coldefs = ast.statements[0].columns; - if (coldefs && coldefs.length > 0) { - coldefs.forEach(function (cd) { - columns.push(cd); - }); - } - }); + getSqlJs(function (SQL) { + var db = new alasql.Database(dbid || sqldbid); + db.engineid = 'SQLITE'; + db.sqldbid = sqldbid; + var sqldb = (db.sqldb = new SQL.Database(data)); + db.tables = []; + var tables = sqldb.exec("SELECT * FROM sqlite_master WHERE type='table'")[0].values; + + tables.forEach(function (tbl) { + db.tables[tbl[1]] = {}; + var columns = (db.tables[tbl[1]].columns = []); + var ast = alasql.parse(tbl[4]); + var coldefs = ast.statements[0].columns; + if (coldefs && coldefs.length > 0) { + coldefs.forEach(function (cd) { + columns.push(cd); + }); + } + }); - cb(1); + cb(1); + }); }, function (err) { throw new Error('Cannot open SQLite database file "' + args[0].value + '"'); diff --git a/test/test1284.js b/test/test1284.js new file mode 100644 index 0000000000..7ab6d9c592 --- /dev/null +++ b/test/test1284.js @@ -0,0 +1,103 @@ +if (typeof exports === 'object') { + var assert = require('assert'); + var alasql = require('..'); +} + +describe('Test 1284 - ATTACH SQLITE DATABASE with async sql.js initialization', function () { + var originalLoadBinaryFile; + var originalSQL; + var originalInitSqlJs; + + class FakeSqlDatabase { + constructor(data) { + this.data = data; + } + + exec(sql) { + if (sql === "SELECT * FROM sqlite_master WHERE type='table'") { + return [ + { + values: [[null, 'signatures', null, null, 'CREATE TABLE signatures (name TEXT)']], + }, + ]; + } + + if (sql === 'SELECT * FROM signatures') { + return [ + { + columns: ['name'], + values: [['Ada']], + }, + ]; + } + + throw new Error('Unexpected SQL: ' + sql); + } + } + + beforeEach(function () { + originalLoadBinaryFile = alasql.utils.loadBinaryFile; + originalSQL = global.SQL; + originalInitSqlJs = global.initSqlJs; + alasql.engines.SQLITE.sqljs = null; + alasql.engines.SQLITE.sqljsPromise = null; + + alasql.utils.loadBinaryFile = function (path, runAsync, success) { + setTimeout(function () { + success('fake sqlite data'); + }, 0); + }; + + global.SQL = function () { + return Promise.resolve({Database: FakeSqlDatabase}); + }; + delete global.initSqlJs; + }); + + afterEach(function () { + alasql.utils.loadBinaryFile = originalLoadBinaryFile; + + if (typeof originalSQL === 'undefined') { + delete global.SQL; + } else { + global.SQL = originalSQL; + } + + if (typeof originalInitSqlJs === 'undefined') { + delete global.initSqlJs; + } else { + global.initSqlJs = originalInitSqlJs; + } + + if (alasql.databases.inscriptions) { + alasql('DETACH DATABASE inscriptions'); + } + alasql.engines.SQLITE.sqljs = null; + alasql.engines.SQLITE.sqljsPromise = null; + }); + + it('supports promise-based sql.js initialization for ATTACH/USE/SELECT', async function () { + const res = await alasql([ + 'ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")', + 'USE inscriptions', + 'SELECT * FROM signatures', + ]); + + assert.deepStrictEqual(res, [1, 1, [{name: 'Ada'}]]); + }); + + it('supports initSqlJs globals used by browser builds', async function () { + delete global.SQL; + global.initSqlJs = function () { + return Promise.resolve({Database: FakeSqlDatabase}); + }; + + const res = await alasql([ + 'ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")', + 'USE inscriptions', + 'SELECT * FROM signatures', + ]); + + assert.deepStrictEqual(res, [1, 1, [{name: 'Ada'}]]); + }); +}); From b1bca93c344704ae64cf3ef7bb089c20b99cb25c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Aug 2026 11:50:20 +0000 Subject: [PATCH 3/8] test: cover async sql.js sqlite attach initialization --- src/93sqljs.js | 92 +++++++++++++++++++++++++++++------------------- test/test1284.js | 66 ++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 36 deletions(-) diff --git a/src/93sqljs.js b/src/93sqljs.js index af18811714..66adfc26c3 100755 --- a/src/93sqljs.js +++ b/src/93sqljs.js @@ -6,42 +6,55 @@ var SQLITE = (alasql.engines.SQLITE = function () {}); -function getSqlJs(cb) { +function getSqlJs(cb, errorcb) { var sqljs = SQLITE.sqljs; var sqljsPromise = SQLITE.sqljsPromise; + var globalSQL = alasql.utils.global.SQL; if (sqljs && sqljs.Database) { cb(sqljs); return; } - if (typeof SQL !== 'undefined' && SQL && SQL.Database) { - SQLITE.sqljs = sqljs = SQL; + if (globalSQL && globalSQL.Database) { + SQLITE.sqljs = sqljs = globalSQL; cb(sqljs); return; } - var initSqlJs = - (typeof SQL !== 'undefined' && typeof SQL === 'function' && SQL) || - alasql.utils.global.initSqlJs; + var initSqlJs = (typeof globalSQL === 'function' && globalSQL) || alasql.utils.global.initSqlJs; if (!initSqlJs) { - throw new Error('SQL.js library is not loaded'); + var err = new Error('SQL.js library is not loaded'); + if (errorcb) { + errorcb(err); + return; + } + throw err; } if (!sqljsPromise) { var initResult = initSqlJs(); - SQLITE.sqljsPromise = sqljsPromise = + var initPromise = initResult && typeof initResult.then === 'function' ? initResult : Promise.resolve(initResult); - SQLITE.sqljsPromise = sqljsPromise = sqljsPromise.then(function (SQL) { - SQLITE.sqljs = sqljs = SQL; - return SQL; - }); + SQLITE.sqljsPromise = sqljsPromise = initPromise + .then(function (sqljsModule) { + if (!sqljsModule || !sqljsModule.Database) { + throw new Error('SQL.js library did not expose a Database constructor'); + } + SQLITE.sqljs = sqljs = sqljsModule; + return sqljsModule; + }) + .catch(function (err) { + SQLITE.sqljs = null; + SQLITE.sqljsPromise = null; + throw err; + }); } - sqljsPromise.then(cb); + sqljsPromise.then(cb, errorcb); } SQLITE.createDatabase = function (wdbid, args, ifnotexists, dbid, cb) { @@ -68,31 +81,38 @@ SQLITE.attachDatabase = function (sqldbid, dbid, args, params, cb) { value, true, function (data) { - getSqlJs(function (SQL) { - var db = new alasql.Database(dbid || sqldbid); - db.engineid = 'SQLITE'; - db.sqldbid = sqldbid; - var sqldb = (db.sqldb = new SQL.Database(data)); - db.tables = []; - var tables = sqldb.exec("SELECT * FROM sqlite_master WHERE type='table'")[0].values; - - tables.forEach(function (tbl) { - db.tables[tbl[1]] = {}; - var columns = (db.tables[tbl[1]].columns = []); - var ast = alasql.parse(tbl[4]); - var coldefs = ast.statements[0].columns; - if (coldefs && coldefs.length > 0) { - coldefs.forEach(function (cd) { - columns.push(cd); - }); - } - }); - - cb(1); - }); + getSqlJs( + function (SQL) { + var db = new alasql.Database(dbid || sqldbid); + db.engineid = 'SQLITE'; + db.sqldbid = sqldbid; + var sqldb = (db.sqldb = new SQL.Database(data)); + db.tables = []; + var tables = sqldb.exec("SELECT * FROM sqlite_master WHERE type='table'")[0].values; + + tables.forEach(function (tbl) { + db.tables[tbl[1]] = {}; + var columns = (db.tables[tbl[1]].columns = []); + var ast = alasql.parse(tbl[4]); + var coldefs = ast.statements[0].columns; + if (coldefs && coldefs.length > 0) { + coldefs.forEach(function (cd) { + columns.push(cd); + }); + } + }); + + cb(1); + }, + function (err) { + cb(null, err); + } + ); }, function (err) { - throw new Error('Cannot open SQLite database file "' + args[0].value + '"'); + var fileError = new Error('Cannot open SQLite database file "' + args[0].value + '"'); + fileError.cause = err; + cb(null, fileError); } ); return res; diff --git a/test/test1284.js b/test/test1284.js index 7ab6d9c592..2cb77ee206 100644 --- a/test/test1284.js +++ b/test/test1284.js @@ -100,4 +100,70 @@ describe('Test 1284 - ATTACH SQLITE DATABASE with async sql.js initialization', assert.deepStrictEqual(res, [1, 1, [{name: 'Ada'}]]); }); + + it('rejects when async sql.js initialization fails', async function () { + delete global.SQL; + global.initSqlJs = function () { + return Promise.reject(new Error('sql.js init failed')); + }; + + await assert.rejects(function () { + return alasql(['ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")']); + }, /sql\.js init failed/); + }); + + it('retries sql.js initialization after a failure', async function () { + delete global.SQL; + var shouldFail = true; + global.initSqlJs = function () { + if (shouldFail) { + return Promise.reject(new Error('sql.js init failed')); + } + return Promise.resolve({Database: FakeSqlDatabase}); + }; + + await assert.rejects(function () { + return alasql(['ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")']); + }, /sql\.js init failed/); + + shouldFail = false; + + const res = await alasql([ + 'ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")', + 'USE inscriptions', + 'SELECT * FROM signatures', + ]); + + assert.deepStrictEqual(res, [1, 1, [{name: 'Ada'}]]); + }); + + it('rejects invalid async sql.js module shapes', async function () { + delete global.SQL; + global.initSqlJs = function () { + return Promise.resolve({}); + }; + + await assert.rejects(function () { + return alasql(['ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")']); + }, /did not expose a Database constructor/); + }); + + it('rejects when the SQLite file cannot be loaded', async function () { + alasql.utils.loadBinaryFile = function (path, runAsync, success, error) { + setTimeout(function () { + error(new Error('load failed')); + }, 0); + }; + + await assert.rejects( + function () { + return alasql(['ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")']); + }, + function (err) { + assert.match(err.message, /Cannot open SQLite database file "mydb\.sqlite3"/); + assert.strictEqual(err.cause.message, 'load failed'); + return true; + } + ); + }); }); From 146478aea37930b649912a302e5cf9c3406a7a30 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Aug 2026 09:02:52 +0000 Subject: [PATCH 4/8] test: simplify async sqlite attach regression Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- test/test1284.js | 135 ++++++++++++++++++++++++----------------------- 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/test/test1284.js b/test/test1284.js index 2cb77ee206..d5b4ab70af 100644 --- a/test/test1284.js +++ b/test/test1284.js @@ -4,6 +4,7 @@ if (typeof exports === 'object') { } describe('Test 1284 - ATTACH SQLITE DATABASE with async sql.js initialization', function () { + var hostGlobals = alasql.utils.global; var originalLoadBinaryFile; var originalSQL; var originalInitSqlJs; @@ -35,117 +36,117 @@ describe('Test 1284 - ATTACH SQLITE DATABASE with async sql.js initialization', } } - beforeEach(function () { - originalLoadBinaryFile = alasql.utils.loadBinaryFile; - originalSQL = global.SQL; - originalInitSqlJs = global.initSqlJs; + function resetSqliteEngineState() { + if (alasql.databases.inscriptions) { + alasql('DETACH DATABASE inscriptions'); + } alasql.engines.SQLITE.sqljs = null; alasql.engines.SQLITE.sqljsPromise = null; + } + + function restoreGlobal(name, value) { + if (typeof value === 'undefined') { + delete hostGlobals[name]; + } else { + hostGlobals[name] = value; + } + } + function mockSqliteFileLoad() { alasql.utils.loadBinaryFile = function (path, runAsync, success) { setTimeout(function () { success('fake sqlite data'); }, 0); }; + } - global.SQL = function () { - return Promise.resolve({Database: FakeSqlDatabase}); - }; - delete global.initSqlJs; - }); - - afterEach(function () { - alasql.utils.loadBinaryFile = originalLoadBinaryFile; + function resolveFakeSqlJsModule() { + return Promise.resolve({Database: FakeSqlDatabase}); + } - if (typeof originalSQL === 'undefined') { - delete global.SQL; - } else { - global.SQL = originalSQL; - } + function useAsyncSqlGlobal() { + hostGlobals.SQL = resolveFakeSqlJsModule; + delete hostGlobals.initSqlJs; + } - if (typeof originalInitSqlJs === 'undefined') { - delete global.initSqlJs; - } else { - global.initSqlJs = originalInitSqlJs; - } + function useBrowserStyleInitSqlJs(initSqlJs) { + delete hostGlobals.SQL; + hostGlobals.initSqlJs = initSqlJs; + } - if (alasql.databases.inscriptions) { - alasql('DETACH DATABASE inscriptions'); - } - alasql.engines.SQLITE.sqljs = null; - alasql.engines.SQLITE.sqljsPromise = null; - }); + function attachDatabase() { + return alasql(['ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")']); + } - it('supports promise-based sql.js initialization for ATTACH/USE/SELECT', async function () { - const res = await alasql([ + function attachUseAndSelect() { + return alasql([ 'ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")', 'USE inscriptions', 'SELECT * FROM signatures', ]); + } + + beforeEach(function () { + originalLoadBinaryFile = alasql.utils.loadBinaryFile; + originalSQL = hostGlobals.SQL; + originalInitSqlJs = hostGlobals.initSqlJs; + resetSqliteEngineState(); + mockSqliteFileLoad(); + useAsyncSqlGlobal(); + }); + + afterEach(function () { + alasql.utils.loadBinaryFile = originalLoadBinaryFile; + restoreGlobal('SQL', originalSQL); + restoreGlobal('initSqlJs', originalInitSqlJs); + resetSqliteEngineState(); + }); + + it('supports promise-based sql.js initialization for ATTACH/USE/SELECT', async function () { + const res = await attachUseAndSelect(); assert.deepStrictEqual(res, [1, 1, [{name: 'Ada'}]]); }); it('supports initSqlJs globals used by browser builds', async function () { - delete global.SQL; - global.initSqlJs = function () { - return Promise.resolve({Database: FakeSqlDatabase}); - }; + useBrowserStyleInitSqlJs(resolveFakeSqlJsModule); - const res = await alasql([ - 'ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")', - 'USE inscriptions', - 'SELECT * FROM signatures', - ]); + const res = await attachUseAndSelect(); assert.deepStrictEqual(res, [1, 1, [{name: 'Ada'}]]); }); it('rejects when async sql.js initialization fails', async function () { - delete global.SQL; - global.initSqlJs = function () { + useBrowserStyleInitSqlJs(function () { return Promise.reject(new Error('sql.js init failed')); - }; + }); - await assert.rejects(function () { - return alasql(['ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")']); - }, /sql\.js init failed/); + await assert.rejects(attachDatabase, /sql\.js init failed/); }); it('retries sql.js initialization after a failure', async function () { - delete global.SQL; - var shouldFail = true; - global.initSqlJs = function () { - if (shouldFail) { + var attempt = 0; + useBrowserStyleInitSqlJs(function () { + attempt += 1; + if (attempt === 1) { return Promise.reject(new Error('sql.js init failed')); } - return Promise.resolve({Database: FakeSqlDatabase}); - }; + return resolveFakeSqlJsModule(); + }); - await assert.rejects(function () { - return alasql(['ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")']); - }, /sql\.js init failed/); + await assert.rejects(attachDatabase, /sql\.js init failed/); - shouldFail = false; - - const res = await alasql([ - 'ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")', - 'USE inscriptions', - 'SELECT * FROM signatures', - ]); + const res = await attachUseAndSelect(); assert.deepStrictEqual(res, [1, 1, [{name: 'Ada'}]]); }); it('rejects invalid async sql.js module shapes', async function () { - delete global.SQL; - global.initSqlJs = function () { + useBrowserStyleInitSqlJs(function () { return Promise.resolve({}); - }; + }); - await assert.rejects(function () { - return alasql(['ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")']); - }, /did not expose a Database constructor/); + await assert.rejects(attachDatabase, /did not expose a Database constructor/); }); it('rejects when the SQLite file cannot be loaded', async function () { From fe7e23948dd3b4246a0f902d50b7652cbeaa1366 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Aug 2026 09:03:25 +0000 Subject: [PATCH 5/8] test: assert sqlite init retries clearly Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- test/test1284.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test1284.js b/test/test1284.js index d5b4ab70af..d0b62f17d1 100644 --- a/test/test1284.js +++ b/test/test1284.js @@ -135,9 +135,11 @@ describe('Test 1284 - ATTACH SQLITE DATABASE with async sql.js initialization', }); await assert.rejects(attachDatabase, /sql\.js init failed/); + assert.strictEqual(attempt, 1); const res = await attachUseAndSelect(); + assert.strictEqual(attempt, 2); assert.deepStrictEqual(res, [1, 1, [{name: 'Ada'}]]); }); From 87bf1f7df72ca821046f94165dbd638c4b89eeca Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Aug 2026 09:46:23 +0000 Subject: [PATCH 6/8] test: simplify async sqlite regression setup Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- test/test1284.js | 79 +++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/test/test1284.js b/test/test1284.js index d0b62f17d1..7b6b80cb05 100644 --- a/test/test1284.js +++ b/test/test1284.js @@ -4,7 +4,6 @@ if (typeof exports === 'object') { } describe('Test 1284 - ATTACH SQLITE DATABASE with async sql.js initialization', function () { - var hostGlobals = alasql.utils.global; var originalLoadBinaryFile; var originalSQL; var originalInitSqlJs; @@ -44,36 +43,10 @@ describe('Test 1284 - ATTACH SQLITE DATABASE with async sql.js initialization', alasql.engines.SQLITE.sqljsPromise = null; } - function restoreGlobal(name, value) { - if (typeof value === 'undefined') { - delete hostGlobals[name]; - } else { - hostGlobals[name] = value; - } - } - - function mockSqliteFileLoad() { - alasql.utils.loadBinaryFile = function (path, runAsync, success) { - setTimeout(function () { - success('fake sqlite data'); - }, 0); - }; - } - - function resolveFakeSqlJsModule() { + function createFakeSqlJsModule() { return Promise.resolve({Database: FakeSqlDatabase}); } - function useAsyncSqlGlobal() { - hostGlobals.SQL = resolveFakeSqlJsModule; - delete hostGlobals.initSqlJs; - } - - function useBrowserStyleInitSqlJs(initSqlJs) { - delete hostGlobals.SQL; - hostGlobals.initSqlJs = initSqlJs; - } - function attachDatabase() { return alasql(['ATTACH SQLITE DATABASE inscriptions("mydb.sqlite3")']); } @@ -88,17 +61,35 @@ describe('Test 1284 - ATTACH SQLITE DATABASE with async sql.js initialization', beforeEach(function () { originalLoadBinaryFile = alasql.utils.loadBinaryFile; - originalSQL = hostGlobals.SQL; - originalInitSqlJs = hostGlobals.initSqlJs; + originalSQL = alasql.utils.global.SQL; + originalInitSqlJs = alasql.utils.global.initSqlJs; resetSqliteEngineState(); - mockSqliteFileLoad(); - useAsyncSqlGlobal(); + + alasql.utils.loadBinaryFile = function (path, runAsync, success) { + setTimeout(function () { + success('fake sqlite data'); + }, 0); + }; + + alasql.utils.global.SQL = createFakeSqlJsModule; + delete alasql.utils.global.initSqlJs; }); afterEach(function () { alasql.utils.loadBinaryFile = originalLoadBinaryFile; - restoreGlobal('SQL', originalSQL); - restoreGlobal('initSqlJs', originalInitSqlJs); + + if (typeof originalSQL === 'undefined') { + delete alasql.utils.global.SQL; + } else { + alasql.utils.global.SQL = originalSQL; + } + + if (typeof originalInitSqlJs === 'undefined') { + delete alasql.utils.global.initSqlJs; + } else { + alasql.utils.global.initSqlJs = originalInitSqlJs; + } + resetSqliteEngineState(); }); @@ -109,7 +100,8 @@ describe('Test 1284 - ATTACH SQLITE DATABASE with async sql.js initialization', }); it('supports initSqlJs globals used by browser builds', async function () { - useBrowserStyleInitSqlJs(resolveFakeSqlJsModule); + delete alasql.utils.global.SQL; + alasql.utils.global.initSqlJs = createFakeSqlJsModule; const res = await attachUseAndSelect(); @@ -117,22 +109,24 @@ describe('Test 1284 - ATTACH SQLITE DATABASE with async sql.js initialization', }); it('rejects when async sql.js initialization fails', async function () { - useBrowserStyleInitSqlJs(function () { + delete alasql.utils.global.SQL; + alasql.utils.global.initSqlJs = function () { return Promise.reject(new Error('sql.js init failed')); - }); + }; await assert.rejects(attachDatabase, /sql\.js init failed/); }); it('retries sql.js initialization after a failure', async function () { var attempt = 0; - useBrowserStyleInitSqlJs(function () { + delete alasql.utils.global.SQL; + alasql.utils.global.initSqlJs = function () { attempt += 1; if (attempt === 1) { return Promise.reject(new Error('sql.js init failed')); } - return resolveFakeSqlJsModule(); - }); + return createFakeSqlJsModule(); + }; await assert.rejects(attachDatabase, /sql\.js init failed/); assert.strictEqual(attempt, 1); @@ -144,9 +138,10 @@ describe('Test 1284 - ATTACH SQLITE DATABASE with async sql.js initialization', }); it('rejects invalid async sql.js module shapes', async function () { - useBrowserStyleInitSqlJs(function () { + delete alasql.utils.global.SQL; + alasql.utils.global.initSqlJs = function () { return Promise.resolve({}); - }); + }; await assert.rejects(attachDatabase, /did not expose a Database constructor/); }); From 5eb549289acab14a430a091e2162063e5d86c7d6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Aug 2026 09:52:02 +0000 Subject: [PATCH 7/8] Use let for attached sqljs database Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/93sqljs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/93sqljs.js b/src/93sqljs.js index 66adfc26c3..e68db7a7f3 100755 --- a/src/93sqljs.js +++ b/src/93sqljs.js @@ -83,7 +83,7 @@ SQLITE.attachDatabase = function (sqldbid, dbid, args, params, cb) { function (data) { getSqlJs( function (SQL) { - var db = new alasql.Database(dbid || sqldbid); + let db = new alasql.Database(dbid || sqldbid); db.engineid = 'SQLITE'; db.sqldbid = sqldbid; var sqldb = (db.sqldb = new SQL.Database(data)); From 24b14ebd4c3477ecde01b5503c92e2b417347c1c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 25 Aug 2026 10:41:12 +0000 Subject: [PATCH 8/8] Use block scoping in sqljs attach path Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/93sqljs.js | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/93sqljs.js b/src/93sqljs.js index e68db7a7f3..519a3e9721 100755 --- a/src/93sqljs.js +++ b/src/93sqljs.js @@ -7,9 +7,9 @@ var SQLITE = (alasql.engines.SQLITE = function () {}); function getSqlJs(cb, errorcb) { - var sqljs = SQLITE.sqljs; - var sqljsPromise = SQLITE.sqljsPromise; - var globalSQL = alasql.utils.global.SQL; + let sqljs = SQLITE.sqljs; + let sqljsPromise = SQLITE.sqljsPromise; + const globalSQL = alasql.utils.global.SQL; if (sqljs && sqljs.Database) { cb(sqljs); @@ -22,10 +22,10 @@ function getSqlJs(cb, errorcb) { return; } - var initSqlJs = (typeof globalSQL === 'function' && globalSQL) || alasql.utils.global.initSqlJs; + const initSqlJs = (typeof globalSQL === 'function' && globalSQL) || alasql.utils.global.initSqlJs; if (!initSqlJs) { - var err = new Error('SQL.js library is not loaded'); + const err = new Error('SQL.js library is not loaded'); if (errorcb) { errorcb(err); return; @@ -34,8 +34,8 @@ function getSqlJs(cb, errorcb) { } if (!sqljsPromise) { - var initResult = initSqlJs(); - var initPromise = + const initResult = initSqlJs(); + const initPromise = initResult && typeof initResult.then === 'function' ? initResult : Promise.resolve(initResult); @@ -72,10 +72,11 @@ SQLITE.attachDatabase = function (sqldbid, dbid, args, params, cb) { } if ((args[0] && args[0] instanceof yy.StringValue) || args[0] instanceof yy.ParamValue) { + let value; if (args[0] instanceof yy.StringValue) { - var value = args[0].value; + value = args[0].value; } else if (args[0] instanceof yy.ParamValue) { - var value = params[args[0].param]; + value = params[args[0].param]; } alasql.utils.loadBinaryFile( value, @@ -83,18 +84,18 @@ SQLITE.attachDatabase = function (sqldbid, dbid, args, params, cb) { function (data) { getSqlJs( function (SQL) { - let db = new alasql.Database(dbid || sqldbid); + const db = new alasql.Database(dbid || sqldbid); db.engineid = 'SQLITE'; db.sqldbid = sqldbid; - var sqldb = (db.sqldb = new SQL.Database(data)); + const sqldb = (db.sqldb = new SQL.Database(data)); db.tables = []; - var tables = sqldb.exec("SELECT * FROM sqlite_master WHERE type='table'")[0].values; + const tables = sqldb.exec("SELECT * FROM sqlite_master WHERE type='table'")[0].values; tables.forEach(function (tbl) { db.tables[tbl[1]] = {}; - var columns = (db.tables[tbl[1]].columns = []); - var ast = alasql.parse(tbl[4]); - var coldefs = ast.statements[0].columns; + const columns = (db.tables[tbl[1]].columns = []); + const ast = alasql.parse(tbl[4]); + const coldefs = ast.statements[0].columns; if (coldefs && coldefs.length > 0) { coldefs.forEach(function (cd) { columns.push(cd); @@ -110,7 +111,7 @@ SQLITE.attachDatabase = function (sqldbid, dbid, args, params, cb) { ); }, function (err) { - var fileError = new Error('Cannot open SQLite database file "' + args[0].value + '"'); + const fileError = new Error('Cannot open SQLite database file "' + args[0].value + '"'); fileError.cause = err; cb(null, fileError); }