@livestore/wa-sqlite 0.0.0-snapshot-b9a2e1dee494215d8c403be013e25cbf4d2cf380
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/dist/README.md +64 -0
- package/dist/fts5/wa-sqlite.mjs +2 -0
- package/dist/fts5/wa-sqlite.node.mjs +2 -0
- package/dist/fts5/wa-sqlite.node.wasm +0 -0
- package/dist/fts5/wa-sqlite.wasm +0 -0
- package/dist/wa-sqlite-async.mjs +2 -0
- package/dist/wa-sqlite-async.wasm +0 -0
- package/dist/wa-sqlite-jspi.mjs +2 -0
- package/dist/wa-sqlite-jspi.wasm +0 -0
- package/dist/wa-sqlite.mjs +2 -0
- package/dist/wa-sqlite.node.mjs +2 -0
- package/dist/wa-sqlite.node.wasm +0 -0
- package/dist/wa-sqlite.wasm +0 -0
- package/package.json +57 -0
- package/src/FacadeVFS.js +681 -0
- package/src/VFS.js +222 -0
- package/src/WebLocksMixin.js +414 -0
- package/src/examples/AccessHandlePoolVFS.js +458 -0
- package/src/examples/IDBBatchAtomicVFS.js +827 -0
- package/src/examples/IDBMirrorVFS.js +889 -0
- package/src/examples/MemoryAsyncVFS.js +100 -0
- package/src/examples/MemoryVFS.js +176 -0
- package/src/examples/OPFSAdaptiveVFS.js +437 -0
- package/src/examples/OPFSAnyContextVFS.js +300 -0
- package/src/examples/OPFSCoopSyncVFS.js +590 -0
- package/src/examples/OPFSPermutedVFS.js +1217 -0
- package/src/examples/README.md +89 -0
- package/src/examples/tag.js +82 -0
- package/src/sqlite-api.js +1339 -0
- package/src/sqlite-constants.js +275 -0
- package/src/types/globals.d.ts +60 -0
- package/src/types/index.d.ts +1531 -0
- package/src/types/tsconfig.json +6 -0
- package/test/AccessHandlePoolVFS.test.js +27 -0
- package/test/IDBBatchAtomicVFS.test.js +97 -0
- package/test/IDBMirrorVFS.test.js +27 -0
- package/test/MemoryAsyncVFS.test.js +27 -0
- package/test/MemoryVFS.test.js +27 -0
- package/test/OPFSAdaptiveVFS.test.js +27 -0
- package/test/OPFSAnyContextVFS.test.js +27 -0
- package/test/OPFSCoopSyncVFS.test.js +27 -0
- package/test/OPFSPermutedVFS.test.js +27 -0
- package/test/TestContext.js +96 -0
- package/test/WebLocksMixin.test.js +521 -0
- package/test/api.test.js +49 -0
- package/test/api_exec.js +89 -0
- package/test/api_misc.js +63 -0
- package/test/api_statements.js +447 -0
- package/test/callbacks.test.js +581 -0
- package/test/data/idbv5.json +1 -0
- package/test/sql.test.js +64 -0
- package/test/sql_0001.js +49 -0
- package/test/sql_0002.js +52 -0
- package/test/sql_0003.js +83 -0
- package/test/sql_0004.js +81 -0
- package/test/sql_0005.js +76 -0
- package/test/test-worker.js +204 -0
- package/test/vfs_xAccess.js +2 -0
- package/test/vfs_xClose.js +52 -0
- package/test/vfs_xOpen.js +91 -0
- package/test/vfs_xRead.js +38 -0
- package/test/vfs_xWrite.js +36 -0
|
@@ -0,0 +1,1339 @@
|
|
|
1
|
+
// Copyright 2021 Roy T. Hashimoto. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
import * as SQLite from './sqlite-constants.js';
|
|
4
|
+
export * from './sqlite-constants.js';
|
|
5
|
+
|
|
6
|
+
const MAX_INT64 = 0x7fffffffffffffffn;
|
|
7
|
+
const MIN_INT64 = -0x8000000000000000n;
|
|
8
|
+
|
|
9
|
+
// const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
|
|
10
|
+
|
|
11
|
+
export class SQLiteError extends Error {
|
|
12
|
+
constructor(message, code) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.code = code;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// const async = true;
|
|
19
|
+
const async = false;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Builds a Javascript API from the Emscripten module. This API is still
|
|
23
|
+
* low-level and closely corresponds to the C API exported by the module,
|
|
24
|
+
* but differs in some specifics like throwing exceptions on errors.
|
|
25
|
+
* @param {*} Module SQLite Emscripten module
|
|
26
|
+
* @returns {SQLiteAPI}
|
|
27
|
+
*/
|
|
28
|
+
export function Factory(Module) {
|
|
29
|
+
/** @type {SQLiteAPI} */ const sqlite3 = {};
|
|
30
|
+
|
|
31
|
+
Module.retryOps = [];
|
|
32
|
+
const sqliteFreeAddress = Module._getSqliteFree();
|
|
33
|
+
|
|
34
|
+
// Allocate some space for 32-bit returned values.
|
|
35
|
+
const tmp = Module._malloc(8);
|
|
36
|
+
const tmpPtr = [tmp, tmp + 4];
|
|
37
|
+
|
|
38
|
+
const textEncoder = new TextEncoder();
|
|
39
|
+
// Convert a JS string to a C string. sqlite3_malloc is used to allocate
|
|
40
|
+
// memory (use sqlite3_free to deallocate).
|
|
41
|
+
function createUTF8(s) {
|
|
42
|
+
if (typeof s !== 'string') return 0;
|
|
43
|
+
const utf8 = textEncoder.encode(s);
|
|
44
|
+
const zts = Module._sqlite3_malloc(utf8.byteLength + 1);
|
|
45
|
+
Module.HEAPU8.set(utf8, zts);
|
|
46
|
+
Module.HEAPU8[zts + utf8.byteLength] = 0;
|
|
47
|
+
return zts;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Concatenate 32-bit numbers into a 64-bit (signed) BigInt.
|
|
52
|
+
* @param {number} lo32
|
|
53
|
+
* @param {number} hi32
|
|
54
|
+
* @returns {bigint}
|
|
55
|
+
*/
|
|
56
|
+
function cvt32x2ToBigInt(lo32, hi32) {
|
|
57
|
+
return (BigInt(hi32) << 32n) | (BigInt(lo32) & 0xffffffffn);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Concatenate 32-bit numbers and return as number or BigInt, depending
|
|
62
|
+
* on the value.
|
|
63
|
+
* @param {number} lo32
|
|
64
|
+
* @param {number} hi32
|
|
65
|
+
* @returns {number|bigint}
|
|
66
|
+
*/
|
|
67
|
+
const cvt32x2AsSafe = (function() {
|
|
68
|
+
const hiMax = BigInt(Number.MAX_SAFE_INTEGER) >> 32n;
|
|
69
|
+
const hiMin = BigInt(Number.MIN_SAFE_INTEGER) >> 32n;
|
|
70
|
+
|
|
71
|
+
return function(lo32, hi32) {
|
|
72
|
+
if (hi32 > hiMax || hi32 < hiMin) {
|
|
73
|
+
// Can't be expressed as a Number so use BigInt.
|
|
74
|
+
return cvt32x2ToBigInt(lo32, hi32);
|
|
75
|
+
} else {
|
|
76
|
+
// Combine the upper and lower 32-bit numbers. The complication is
|
|
77
|
+
// that lo32 is a signed integer which makes manipulating its bits
|
|
78
|
+
// a little tricky - the sign bit gets handled separately.
|
|
79
|
+
return (hi32 * 0x100000000) + (lo32 & 0x7fffffff) - (lo32 & 0x80000000);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
})();
|
|
83
|
+
|
|
84
|
+
const databases = new Set();
|
|
85
|
+
function verifyDatabase(db) {
|
|
86
|
+
if (!databases.has(db)) {
|
|
87
|
+
throw new SQLiteError('not a database', SQLite.SQLITE_MISUSE);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const mapStmtToDB = new Map();
|
|
92
|
+
function verifyStatement(stmt) {
|
|
93
|
+
if (!mapStmtToDB.has(stmt)) {
|
|
94
|
+
throw new SQLiteError('not a statement', SQLite.SQLITE_MISUSE);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
sqlite3.bind_collection = function(stmt, bindings) {
|
|
99
|
+
verifyStatement(stmt);
|
|
100
|
+
const isArray = Array.isArray(bindings);
|
|
101
|
+
const nBindings = sqlite3.bind_parameter_count(stmt);
|
|
102
|
+
for (let i = 1; i <= nBindings; ++i) {
|
|
103
|
+
const key = isArray ? i - 1 : sqlite3.bind_parameter_name(stmt, i);
|
|
104
|
+
const value = bindings[key];
|
|
105
|
+
if (value !== undefined) {
|
|
106
|
+
sqlite3.bind(stmt, i, value);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return SQLite.SQLITE_OK;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
sqlite3.bind = function(stmt, i, value) {
|
|
113
|
+
verifyStatement(stmt);
|
|
114
|
+
switch (typeof value) {
|
|
115
|
+
case 'number':
|
|
116
|
+
if (value === (value | 0)) {
|
|
117
|
+
return sqlite3.bind_int(stmt, i, value);
|
|
118
|
+
} else {
|
|
119
|
+
return sqlite3.bind_double(stmt, i, value);
|
|
120
|
+
}
|
|
121
|
+
case 'string':
|
|
122
|
+
return sqlite3.bind_text(stmt, i, value);
|
|
123
|
+
case "boolean":
|
|
124
|
+
return sqlite3.bind_int(stmt, i, value ? 1 : 0);
|
|
125
|
+
default:
|
|
126
|
+
if (value instanceof Uint8Array || Array.isArray(value)) {
|
|
127
|
+
return sqlite3.bind_blob(stmt, i, value);
|
|
128
|
+
} else if (value === null) {
|
|
129
|
+
return sqlite3.bind_null(stmt, i);
|
|
130
|
+
} else if (typeof value === 'bigint') {
|
|
131
|
+
return sqlite3.bind_int64(stmt, i, value);
|
|
132
|
+
} else if (value === undefined) {
|
|
133
|
+
// Existing binding (or NULL) will be used.
|
|
134
|
+
return SQLite.SQLITE_NOTICE;
|
|
135
|
+
} else {
|
|
136
|
+
console.warn('unknown binding converted to null', value);
|
|
137
|
+
return sqlite3.bind_null(stmt, i);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
sqlite3.bind_blob = (function() {
|
|
143
|
+
const fname = 'sqlite3_bind_blob';
|
|
144
|
+
const f = Module.cwrap(fname, ...decl('nnnnn:n'));
|
|
145
|
+
return function(stmt, i, value) {
|
|
146
|
+
verifyStatement(stmt);
|
|
147
|
+
// @ts-ignore
|
|
148
|
+
const byteLength = value.byteLength ?? value.length;
|
|
149
|
+
const ptr = Module._sqlite3_malloc(byteLength);
|
|
150
|
+
Module.HEAPU8.subarray(ptr).set(value);
|
|
151
|
+
const result = f(stmt, i, ptr, byteLength, sqliteFreeAddress);
|
|
152
|
+
return check(fname, result, mapStmtToDB.get(stmt));
|
|
153
|
+
};
|
|
154
|
+
})();
|
|
155
|
+
|
|
156
|
+
sqlite3.bind_parameter_count = (function() {
|
|
157
|
+
const fname = 'sqlite3_bind_parameter_count';
|
|
158
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
159
|
+
return function(stmt) {
|
|
160
|
+
verifyStatement(stmt);
|
|
161
|
+
const result = f(stmt);
|
|
162
|
+
return result;
|
|
163
|
+
};
|
|
164
|
+
})();
|
|
165
|
+
|
|
166
|
+
sqlite3.bind_double = (function() {
|
|
167
|
+
const fname = 'sqlite3_bind_double';
|
|
168
|
+
const f = Module.cwrap(fname, ...decl('nnn:n'));
|
|
169
|
+
return function(stmt, i, value) {
|
|
170
|
+
verifyStatement(stmt);
|
|
171
|
+
const result = f(stmt, i, value);
|
|
172
|
+
return check(fname, result, mapStmtToDB.get(stmt));
|
|
173
|
+
};
|
|
174
|
+
})();
|
|
175
|
+
|
|
176
|
+
sqlite3.bind_int = (function() {
|
|
177
|
+
const fname = 'sqlite3_bind_int';
|
|
178
|
+
const f = Module.cwrap(fname, ...decl('nnn:n'));
|
|
179
|
+
return function(stmt, i, value) {
|
|
180
|
+
verifyStatement(stmt);
|
|
181
|
+
if (value > 0x7fffffff || value < -0x80000000) return SQLite.SQLITE_RANGE;
|
|
182
|
+
|
|
183
|
+
const result = f(stmt, i, value);
|
|
184
|
+
return check(fname, result, mapStmtToDB.get(stmt));
|
|
185
|
+
};
|
|
186
|
+
})();
|
|
187
|
+
|
|
188
|
+
sqlite3.bind_int64 = (function() {
|
|
189
|
+
const fname = 'sqlite3_bind_int64';
|
|
190
|
+
const f = Module.cwrap(fname, ...decl('nnnn:n'));
|
|
191
|
+
return function(stmt, i, value) {
|
|
192
|
+
verifyStatement(stmt);
|
|
193
|
+
if (value > MAX_INT64 || value < MIN_INT64) return SQLite.SQLITE_RANGE;
|
|
194
|
+
|
|
195
|
+
const lo32 = value & 0xffffffffn;
|
|
196
|
+
const hi32 = value >> 32n;
|
|
197
|
+
const result = f(stmt, i, Number(lo32), Number(hi32));
|
|
198
|
+
return check(fname, result, mapStmtToDB.get(stmt));
|
|
199
|
+
};
|
|
200
|
+
})();
|
|
201
|
+
|
|
202
|
+
sqlite3.bind_null = (function() {
|
|
203
|
+
const fname = 'sqlite3_bind_null';
|
|
204
|
+
const f = Module.cwrap(fname, ...decl('nn:n'));
|
|
205
|
+
return function(stmt, i) {
|
|
206
|
+
verifyStatement(stmt);
|
|
207
|
+
const result = f(stmt, i);
|
|
208
|
+
return check(fname, result, mapStmtToDB.get(stmt));
|
|
209
|
+
};
|
|
210
|
+
})();
|
|
211
|
+
|
|
212
|
+
sqlite3.bind_parameter_name = (function() {
|
|
213
|
+
const fname = 'sqlite3_bind_parameter_name';
|
|
214
|
+
const f = Module.cwrap(fname, ...decl('n:s'));
|
|
215
|
+
return function(stmt, i) {
|
|
216
|
+
verifyStatement(stmt);
|
|
217
|
+
const result = f(stmt, i);
|
|
218
|
+
return result;
|
|
219
|
+
};
|
|
220
|
+
})();
|
|
221
|
+
|
|
222
|
+
sqlite3.bind_text = (function() {
|
|
223
|
+
const fname = 'sqlite3_bind_text';
|
|
224
|
+
const f = Module.cwrap(fname, ...decl('nnnnn:n'));
|
|
225
|
+
return function(stmt, i, value) {
|
|
226
|
+
verifyStatement(stmt);
|
|
227
|
+
const ptr = createUTF8(value);
|
|
228
|
+
const result = f(stmt, i, ptr, -1, sqliteFreeAddress);
|
|
229
|
+
return check(fname, result, mapStmtToDB.get(stmt));
|
|
230
|
+
};
|
|
231
|
+
})();
|
|
232
|
+
|
|
233
|
+
sqlite3.changes = (function() {
|
|
234
|
+
const fname = 'sqlite3_changes';
|
|
235
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
236
|
+
return function(db) {
|
|
237
|
+
verifyDatabase(db);
|
|
238
|
+
const result = f(db);
|
|
239
|
+
return result;
|
|
240
|
+
};
|
|
241
|
+
})();
|
|
242
|
+
|
|
243
|
+
sqlite3.deserialize = (function() {
|
|
244
|
+
const fname = 'sqlite3_deserialize';
|
|
245
|
+
const f = Module.cwrap(fname, ...decl('nnnnnn:n'));
|
|
246
|
+
return function(db, schema, data, szDb, szBuf, flags) {
|
|
247
|
+
verifyDatabase(db);
|
|
248
|
+
const ptr = Module._sqlite3_malloc(szDb);
|
|
249
|
+
Module.HEAPU8.subarray(ptr).set(data);
|
|
250
|
+
const result = f(db, schema, ptr, szDb, szBuf, flags);
|
|
251
|
+
return result;
|
|
252
|
+
};
|
|
253
|
+
})();
|
|
254
|
+
|
|
255
|
+
const SQLITE_SERIALIZE_NOCOPY = 0x0_01
|
|
256
|
+
|
|
257
|
+
sqlite3.serialize = (function() {
|
|
258
|
+
const fname = 'sqlite3_serialize';
|
|
259
|
+
const f = Module.cwrap(fname, ...decl('nsnn:n'));
|
|
260
|
+
return function(db, schema) {
|
|
261
|
+
verifyDatabase(db);
|
|
262
|
+
const piSize = tmpPtr[0];
|
|
263
|
+
let address = f(db, schema, piSize, 0); // 0 means no flags
|
|
264
|
+
if (address === 0) {
|
|
265
|
+
address = f(db, schema, piSize, SQLITE_SERIALIZE_NOCOPY);
|
|
266
|
+
const size = Module.getValue(piSize, '*');
|
|
267
|
+
const result = Module.HEAPU8.subarray(address, address + size);
|
|
268
|
+
// NOTE Given that the memory is owned by SQLite, we must copy it.
|
|
269
|
+
// Warning: We're not super confident yet about this code path. There might be dragons.
|
|
270
|
+
return new Uint8Array(result.slice());
|
|
271
|
+
} else {
|
|
272
|
+
const size = Module.getValue(piSize, '*');
|
|
273
|
+
const result = Module.HEAPU8.subarray(address, address + size);
|
|
274
|
+
// Copy the data immediately, then free the SQLite buffer to prevent ref-count issues
|
|
275
|
+
const copy = new Uint8Array(result);
|
|
276
|
+
Module._sqlite3_free(address);
|
|
277
|
+
return copy;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
})();
|
|
281
|
+
|
|
282
|
+
// https://www.sqlite.org/c3ref/backup_finish.html
|
|
283
|
+
// https://www.sqlite.org/backup.html
|
|
284
|
+
sqlite3.backup = (function() {
|
|
285
|
+
const fInit = Module.cwrap('sqlite3_backup_init', ...decl('nsns:n'));
|
|
286
|
+
const fStep = Module.cwrap('sqlite3_backup_step', ...decl('nn:n'));
|
|
287
|
+
const fFinish = Module.cwrap('sqlite3_backup_finish', ...decl('n:n'));
|
|
288
|
+
return function(dest, destName, source, sourceName) {
|
|
289
|
+
verifyDatabase(dest);
|
|
290
|
+
verifyDatabase(source);
|
|
291
|
+
const backup = fInit(dest, destName, source, sourceName);
|
|
292
|
+
if (backup === 0) {
|
|
293
|
+
const errMsg = Module.ccall('sqlite3_errmsg', 'string', ['number'], [dest]);
|
|
294
|
+
throw new SQLiteError(`backup failed: ${errMsg}`, SQLite.SQLITE_ERROR);
|
|
295
|
+
}
|
|
296
|
+
// TODO also allow run in chunks with some yielding mechanism
|
|
297
|
+
fStep(backup, -1); // -1 means do it in one go
|
|
298
|
+
return fFinish(backup);
|
|
299
|
+
};
|
|
300
|
+
})();
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
// TODO implement this at some point
|
|
304
|
+
// sqlite3.backup_step = (function() {
|
|
305
|
+
|
|
306
|
+
sqlite3.clear_bindings = (function() {
|
|
307
|
+
const fname = 'sqlite3_clear_bindings';
|
|
308
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
309
|
+
return function(stmt) {
|
|
310
|
+
verifyStatement(stmt);
|
|
311
|
+
const result = f(stmt);
|
|
312
|
+
return check(fname, result, mapStmtToDB.get(stmt));
|
|
313
|
+
};
|
|
314
|
+
})();
|
|
315
|
+
|
|
316
|
+
sqlite3.close = (function() {
|
|
317
|
+
const fname = 'sqlite3_close';
|
|
318
|
+
const f = Module.cwrap(fname, ...decl('n:n'), { async });
|
|
319
|
+
// return async function(db) {
|
|
320
|
+
return function(db) {
|
|
321
|
+
verifyDatabase(db);
|
|
322
|
+
// const result = await f(db);
|
|
323
|
+
const result = f(db);
|
|
324
|
+
databases.delete(db);
|
|
325
|
+
return check(fname, result, db);
|
|
326
|
+
};
|
|
327
|
+
})();
|
|
328
|
+
|
|
329
|
+
sqlite3.column = function(stmt, iCol) {
|
|
330
|
+
verifyStatement(stmt);
|
|
331
|
+
const type = sqlite3.column_type(stmt, iCol);
|
|
332
|
+
switch (type) {
|
|
333
|
+
case SQLite.SQLITE_BLOB:
|
|
334
|
+
return sqlite3.column_blob(stmt, iCol);
|
|
335
|
+
case SQLite.SQLITE_FLOAT:
|
|
336
|
+
return sqlite3.column_double(stmt, iCol);
|
|
337
|
+
case SQLite.SQLITE_INTEGER:
|
|
338
|
+
const lo32 = sqlite3.column_int(stmt, iCol);
|
|
339
|
+
const hi32 = Module.getTempRet0();
|
|
340
|
+
return cvt32x2AsSafe(lo32, hi32);
|
|
341
|
+
case SQLite.SQLITE_NULL:
|
|
342
|
+
return null;
|
|
343
|
+
case SQLite.SQLITE_TEXT:
|
|
344
|
+
return sqlite3.column_text(stmt, iCol);
|
|
345
|
+
default:
|
|
346
|
+
throw new SQLiteError('unknown type', type);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
sqlite3.column_blob = (function() {
|
|
351
|
+
const fname = 'sqlite3_column_blob';
|
|
352
|
+
const f = Module.cwrap(fname, ...decl('nn:n'));
|
|
353
|
+
return function(stmt, iCol) {
|
|
354
|
+
verifyStatement(stmt);
|
|
355
|
+
const nBytes = sqlite3.column_bytes(stmt, iCol);
|
|
356
|
+
const address = f(stmt, iCol);
|
|
357
|
+
if (address === 0) {
|
|
358
|
+
return null; // Handle NULL BLOBs
|
|
359
|
+
}
|
|
360
|
+
const result = Module.HEAPU8.subarray(address, address + nBytes);
|
|
361
|
+
return new Uint8Array(result); // Ensure a copy is returned
|
|
362
|
+
};
|
|
363
|
+
})();
|
|
364
|
+
|
|
365
|
+
sqlite3.column_bytes = (function() {
|
|
366
|
+
const fname = 'sqlite3_column_bytes';
|
|
367
|
+
const f = Module.cwrap(fname, ...decl('nn:n'));
|
|
368
|
+
return function(stmt, iCol) {
|
|
369
|
+
verifyStatement(stmt);
|
|
370
|
+
const result = f(stmt, iCol);
|
|
371
|
+
return result;
|
|
372
|
+
};
|
|
373
|
+
})();
|
|
374
|
+
|
|
375
|
+
sqlite3.column_count = (function() {
|
|
376
|
+
const fname = 'sqlite3_column_count';
|
|
377
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
378
|
+
return function(stmt) {
|
|
379
|
+
verifyStatement(stmt);
|
|
380
|
+
const result = f(stmt);
|
|
381
|
+
return result;
|
|
382
|
+
};
|
|
383
|
+
})();
|
|
384
|
+
|
|
385
|
+
sqlite3.column_double = (function() {
|
|
386
|
+
const fname = 'sqlite3_column_double';
|
|
387
|
+
const f = Module.cwrap(fname, ...decl('nn:n'));
|
|
388
|
+
return function(stmt, iCol) {
|
|
389
|
+
verifyStatement(stmt);
|
|
390
|
+
const result = f(stmt, iCol);
|
|
391
|
+
return result;
|
|
392
|
+
};
|
|
393
|
+
})();
|
|
394
|
+
|
|
395
|
+
sqlite3.column_int = (function() {
|
|
396
|
+
// Retrieve int64 but use only the lower 32 bits. The upper 32-bits are
|
|
397
|
+
// accessible with Module.getTempRet0().
|
|
398
|
+
const fname = 'sqlite3_column_int64';
|
|
399
|
+
const f = Module.cwrap(fname, ...decl('nn:n'));
|
|
400
|
+
return function(stmt, iCol) {
|
|
401
|
+
verifyStatement(stmt);
|
|
402
|
+
const result = f(stmt, iCol);
|
|
403
|
+
return result;
|
|
404
|
+
};
|
|
405
|
+
})();
|
|
406
|
+
|
|
407
|
+
sqlite3.column_int64 = (function() {
|
|
408
|
+
const fname = 'sqlite3_column_int64';
|
|
409
|
+
const f = Module.cwrap(fname, ...decl('nn:n'));
|
|
410
|
+
return function(stmt, iCol) {
|
|
411
|
+
verifyStatement(stmt);
|
|
412
|
+
const lo32 = f(stmt, iCol);
|
|
413
|
+
const hi32 = Module.getTempRet0();
|
|
414
|
+
const result = cvt32x2ToBigInt(lo32, hi32);
|
|
415
|
+
return result;
|
|
416
|
+
};
|
|
417
|
+
})();
|
|
418
|
+
|
|
419
|
+
sqlite3.column_name = (function() {
|
|
420
|
+
const fname = 'sqlite3_column_name';
|
|
421
|
+
const f = Module.cwrap(fname, ...decl('nn:s'));
|
|
422
|
+
return function(stmt, iCol) {
|
|
423
|
+
verifyStatement(stmt);
|
|
424
|
+
const result = f(stmt, iCol);
|
|
425
|
+
return result;
|
|
426
|
+
};
|
|
427
|
+
})();
|
|
428
|
+
|
|
429
|
+
sqlite3.column_names = function(stmt) {
|
|
430
|
+
const columns = [];
|
|
431
|
+
const nColumns = sqlite3.column_count(stmt);
|
|
432
|
+
for (let i = 0; i < nColumns; ++i) {
|
|
433
|
+
columns.push(sqlite3.column_name(stmt, i));
|
|
434
|
+
}
|
|
435
|
+
return columns;
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
sqlite3.column_text = (function() {
|
|
439
|
+
const fname = 'sqlite3_column_text';
|
|
440
|
+
const f = Module.cwrap(fname, ...decl('nn:s'));
|
|
441
|
+
return function(stmt, iCol) {
|
|
442
|
+
verifyStatement(stmt);
|
|
443
|
+
const result = f(stmt, iCol);
|
|
444
|
+
return result;
|
|
445
|
+
};
|
|
446
|
+
})();
|
|
447
|
+
|
|
448
|
+
sqlite3.column_type = (function() {
|
|
449
|
+
const fname = 'sqlite3_column_type';
|
|
450
|
+
const f = Module.cwrap(fname, ...decl('nn:n'));
|
|
451
|
+
return function(stmt, iCol) {
|
|
452
|
+
verifyStatement(stmt);
|
|
453
|
+
const result = f(stmt, iCol);
|
|
454
|
+
return result;
|
|
455
|
+
};
|
|
456
|
+
})();
|
|
457
|
+
|
|
458
|
+
sqlite3.create_function = function(db, zFunctionName, nArg, eTextRep, pApp, xFunc, xStep, xFinal) {
|
|
459
|
+
verifyDatabase(db);
|
|
460
|
+
|
|
461
|
+
// Convert SQLite callback arguments to JavaScript-friendly arguments.
|
|
462
|
+
function adapt(f) {
|
|
463
|
+
// return f instanceof AsyncFunction ?
|
|
464
|
+
// (async (ctx, n, values) => f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n))) :
|
|
465
|
+
// ((ctx, n, values) => f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n)));
|
|
466
|
+
return ((ctx, n, values) => f(ctx, Module.HEAP32.subarray(values / 4, values / 4 + n)));
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const result = Module.create_function(
|
|
470
|
+
db,
|
|
471
|
+
zFunctionName,
|
|
472
|
+
nArg,
|
|
473
|
+
eTextRep,
|
|
474
|
+
pApp,
|
|
475
|
+
xFunc && adapt(xFunc),
|
|
476
|
+
xStep && adapt(xStep),
|
|
477
|
+
xFinal);
|
|
478
|
+
return check('sqlite3_create_function', result, db);
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
sqlite3.data_count = (function() {
|
|
482
|
+
const fname = 'sqlite3_data_count';
|
|
483
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
484
|
+
return function(stmt) {
|
|
485
|
+
verifyStatement(stmt);
|
|
486
|
+
const result = f(stmt);
|
|
487
|
+
return result;
|
|
488
|
+
};
|
|
489
|
+
})();
|
|
490
|
+
|
|
491
|
+
// sqlite3.exec = async function(db, sql, callback) {
|
|
492
|
+
// for await (const stmt of sqlite3.statements(db, sql)) {
|
|
493
|
+
// let columns;
|
|
494
|
+
// while (await sqlite3.step(stmt) === SQLite.SQLITE_ROW) {
|
|
495
|
+
// if (callback) {
|
|
496
|
+
// columns = columns ?? sqlite3.column_names(stmt);
|
|
497
|
+
// const row = sqlite3.row(stmt);
|
|
498
|
+
// await callback(row, columns);
|
|
499
|
+
// }
|
|
500
|
+
// }
|
|
501
|
+
// }
|
|
502
|
+
// return SQLite.SQLITE_OK;
|
|
503
|
+
// };
|
|
504
|
+
sqlite3.exec = function(db, sql, callback) {
|
|
505
|
+
const stmts = sqlite3.statements(db, sql, { unscoped: true });
|
|
506
|
+
for (const stmt of stmts) {
|
|
507
|
+
let columns;
|
|
508
|
+
while (sqlite3.step(stmt) === SQLite.SQLITE_ROW) {
|
|
509
|
+
if (callback) {
|
|
510
|
+
columns = columns ?? sqlite3.column_names(stmt);
|
|
511
|
+
const row = sqlite3.row(stmt);
|
|
512
|
+
callback(row, columns);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
for (const stmt of stmts) {
|
|
517
|
+
sqlite3.finalize(stmt);
|
|
518
|
+
}
|
|
519
|
+
return SQLite.SQLITE_OK;
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
sqlite3.finalize = (function() {
|
|
523
|
+
const fname = 'sqlite3_finalize';
|
|
524
|
+
const f = Module.cwrap(fname, ...decl('n:n'), { async });
|
|
525
|
+
// return async function(stmt) {
|
|
526
|
+
// const result = await f(stmt);
|
|
527
|
+
return function(stmt) {
|
|
528
|
+
const result = f(stmt);
|
|
529
|
+
mapStmtToDB.delete(stmt)
|
|
530
|
+
|
|
531
|
+
// Don't throw on error here. Typically the error has already been
|
|
532
|
+
// thrown and finalize() is part of the cleanup.
|
|
533
|
+
return result;
|
|
534
|
+
};
|
|
535
|
+
})();
|
|
536
|
+
|
|
537
|
+
sqlite3.get_autocommit = (function() {
|
|
538
|
+
const fname = 'sqlite3_get_autocommit';
|
|
539
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
540
|
+
return function(db) {
|
|
541
|
+
const result = f(db);
|
|
542
|
+
return result;
|
|
543
|
+
};
|
|
544
|
+
})();
|
|
545
|
+
|
|
546
|
+
sqlite3.libversion = (function() {
|
|
547
|
+
const fname = 'sqlite3_libversion';
|
|
548
|
+
const f = Module.cwrap(fname, ...decl(':s'));
|
|
549
|
+
return function() {
|
|
550
|
+
const result = f();
|
|
551
|
+
return result;
|
|
552
|
+
};
|
|
553
|
+
})();
|
|
554
|
+
|
|
555
|
+
sqlite3.libversion_number = (function() {
|
|
556
|
+
const fname = 'sqlite3_libversion_number';
|
|
557
|
+
const f = Module.cwrap(fname, ...decl(':n'));
|
|
558
|
+
return function() {
|
|
559
|
+
const result = f();
|
|
560
|
+
return result;
|
|
561
|
+
};
|
|
562
|
+
})();
|
|
563
|
+
|
|
564
|
+
sqlite3.limit = (function() {
|
|
565
|
+
const fname = 'sqlite3_limit';
|
|
566
|
+
const f = Module.cwrap(fname, ...decl('nnn:n'));
|
|
567
|
+
return function(db, id, newVal) {
|
|
568
|
+
const result = f(db, id, newVal);
|
|
569
|
+
return result;
|
|
570
|
+
};
|
|
571
|
+
})();
|
|
572
|
+
|
|
573
|
+
sqlite3.open_v2 = (function() {
|
|
574
|
+
const fname = 'sqlite3_open_v2';
|
|
575
|
+
const f = Module.cwrap(fname, ...decl('snnn:n'), { async });
|
|
576
|
+
return async function(zFilename, flags, zVfs) {
|
|
577
|
+
flags = flags || SQLite.SQLITE_OPEN_CREATE | SQLite.SQLITE_OPEN_READWRITE;
|
|
578
|
+
zVfs = createUTF8(zVfs);
|
|
579
|
+
try {
|
|
580
|
+
// Allow retry operations.
|
|
581
|
+
const rc = await retry(() => f(zFilename, tmpPtr[0], flags, zVfs));
|
|
582
|
+
|
|
583
|
+
const db = Module.getValue(tmpPtr[0], '*');
|
|
584
|
+
databases.add(db);
|
|
585
|
+
|
|
586
|
+
Module.ccall('RegisterExtensionFunctions', 'void', ['number'], [db]);
|
|
587
|
+
check(fname, rc, db);
|
|
588
|
+
return db;
|
|
589
|
+
} finally {
|
|
590
|
+
Module._sqlite3_free(zVfs);
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
})();
|
|
594
|
+
|
|
595
|
+
sqlite3.open_v2Sync = (function() {
|
|
596
|
+
const fname = 'sqlite3_open_v2';
|
|
597
|
+
const f = Module.cwrap(fname, ...decl('snnn:n'), { async });
|
|
598
|
+
return function(zFilename, flags, zVfs) {
|
|
599
|
+
flags = flags || SQLite.SQLITE_OPEN_CREATE | SQLite.SQLITE_OPEN_READWRITE;
|
|
600
|
+
zVfs = createUTF8(zVfs);
|
|
601
|
+
try {
|
|
602
|
+
// Allow retry operations.
|
|
603
|
+
// const rc = await retry(() => f(zFilename, tmpPtr[0], flags, zVfs));
|
|
604
|
+
const rc = f(zFilename, tmpPtr[0], flags, zVfs);
|
|
605
|
+
|
|
606
|
+
const db = Module.getValue(tmpPtr[0], '*');
|
|
607
|
+
databases.add(db);
|
|
608
|
+
|
|
609
|
+
Module.ccall('RegisterExtensionFunctions', 'void', ['number'], [db]);
|
|
610
|
+
check(fname, rc, db);
|
|
611
|
+
return db;
|
|
612
|
+
} finally {
|
|
613
|
+
Module._sqlite3_free(zVfs);
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
})();
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
sqlite3.progress_handler = function(db, nProgressOps, handler, userData) {
|
|
620
|
+
verifyDatabase(db);
|
|
621
|
+
Module.progress_handler(db, nProgressOps, handler, userData);
|
|
622
|
+
};;
|
|
623
|
+
|
|
624
|
+
sqlite3.reset = (function() {
|
|
625
|
+
const fname = 'sqlite3_reset';
|
|
626
|
+
const f = Module.cwrap(fname, ...decl('n:n'), { async });
|
|
627
|
+
return function(stmt) {
|
|
628
|
+
verifyStatement(stmt);
|
|
629
|
+
const result = f(stmt);
|
|
630
|
+
return check(fname, result, mapStmtToDB.get(stmt));
|
|
631
|
+
};
|
|
632
|
+
})();
|
|
633
|
+
|
|
634
|
+
sqlite3.result = function(context, value) {
|
|
635
|
+
switch (typeof value) {
|
|
636
|
+
case 'number':
|
|
637
|
+
if (value === (value | 0)) {
|
|
638
|
+
sqlite3.result_int(context, value);
|
|
639
|
+
} else {
|
|
640
|
+
sqlite3.result_double(context, value);
|
|
641
|
+
}
|
|
642
|
+
break;
|
|
643
|
+
case 'string':
|
|
644
|
+
sqlite3.result_text(context, value);
|
|
645
|
+
break;
|
|
646
|
+
default:
|
|
647
|
+
if (value instanceof Uint8Array || Array.isArray(value)) {
|
|
648
|
+
sqlite3.result_blob(context, value);
|
|
649
|
+
} else if (value === null) {
|
|
650
|
+
sqlite3.result_null(context);
|
|
651
|
+
} else if (typeof value === 'bigint') {
|
|
652
|
+
return sqlite3.result_int64(context, value);
|
|
653
|
+
} else {
|
|
654
|
+
console.warn('unknown result converted to null', value);
|
|
655
|
+
sqlite3.result_null(context);
|
|
656
|
+
}
|
|
657
|
+
break;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
sqlite3.result_blob = (function() {
|
|
663
|
+
const fname = 'sqlite3_result_blob';
|
|
664
|
+
const f = Module.cwrap(fname, ...decl('nnnn:n'));
|
|
665
|
+
return function(context, value) {
|
|
666
|
+
// @ts-ignore
|
|
667
|
+
const byteLength = value.byteLength ?? value.length;
|
|
668
|
+
const ptr = Module._sqlite3_malloc(byteLength);
|
|
669
|
+
Module.HEAPU8.subarray(ptr).set(value);
|
|
670
|
+
f(context, ptr, byteLength, sqliteFreeAddress); // void return
|
|
671
|
+
};
|
|
672
|
+
})();
|
|
673
|
+
|
|
674
|
+
sqlite3.result_double = (function() {
|
|
675
|
+
const fname = 'sqlite3_result_double';
|
|
676
|
+
const f = Module.cwrap(fname, ...decl('nn:n'));
|
|
677
|
+
return function(context, value) {
|
|
678
|
+
f(context, value); // void return
|
|
679
|
+
};
|
|
680
|
+
})();
|
|
681
|
+
|
|
682
|
+
sqlite3.result_int = (function() {
|
|
683
|
+
const fname = 'sqlite3_result_int';
|
|
684
|
+
const f = Module.cwrap(fname, ...decl('nn:n'));
|
|
685
|
+
return function(context, value) {
|
|
686
|
+
f(context, value); // void return
|
|
687
|
+
};
|
|
688
|
+
})();
|
|
689
|
+
|
|
690
|
+
sqlite3.result_int64 = (function() {
|
|
691
|
+
const fname = 'sqlite3_result_int64';
|
|
692
|
+
const f = Module.cwrap(fname, ...decl('nnn:n'));
|
|
693
|
+
return function(context, value) {
|
|
694
|
+
if (value > MAX_INT64 || value < MIN_INT64) return SQLite.SQLITE_RANGE;
|
|
695
|
+
|
|
696
|
+
const lo32 = value & 0xffffffffn;
|
|
697
|
+
const hi32 = value >> 32n;
|
|
698
|
+
f(context, Number(lo32), Number(hi32)); // void return
|
|
699
|
+
};
|
|
700
|
+
})();
|
|
701
|
+
|
|
702
|
+
sqlite3.result_null = (function() {
|
|
703
|
+
const fname = 'sqlite3_result_null';
|
|
704
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
705
|
+
return function(context) {
|
|
706
|
+
f(context); // void return
|
|
707
|
+
};
|
|
708
|
+
})();
|
|
709
|
+
|
|
710
|
+
sqlite3.result_text = (function() {
|
|
711
|
+
const fname = 'sqlite3_result_text';
|
|
712
|
+
const f = Module.cwrap(fname, ...decl('nnnn:n'));
|
|
713
|
+
return function(context, value) {
|
|
714
|
+
const ptr = createUTF8(value);
|
|
715
|
+
f(context, ptr, -1, sqliteFreeAddress); // void return
|
|
716
|
+
};
|
|
717
|
+
})();
|
|
718
|
+
|
|
719
|
+
sqlite3.row = function(stmt) {
|
|
720
|
+
const row = [];
|
|
721
|
+
const nColumns = sqlite3.data_count(stmt);
|
|
722
|
+
for (let i = 0; i < nColumns; ++i) {
|
|
723
|
+
const value = sqlite3.column(stmt, i);
|
|
724
|
+
|
|
725
|
+
// Copy blob if aliasing volatile WebAssembly memory. This avoids an
|
|
726
|
+
// unnecessary copy if users monkey patch column_blob to copy.
|
|
727
|
+
// @ts-ignore
|
|
728
|
+
row.push(value?.buffer === Module.HEAPU8.buffer ? value.slice() : value);
|
|
729
|
+
}
|
|
730
|
+
return row;
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
sqlite3.set_authorizer = function(db, xAuth, pApp) {
|
|
734
|
+
verifyDatabase(db);
|
|
735
|
+
|
|
736
|
+
// Convert SQLite callback arguments to JavaScript-friendly arguments.
|
|
737
|
+
function cvtArgs(_, iAction, p3, p4, p5, p6) {
|
|
738
|
+
return [
|
|
739
|
+
_,
|
|
740
|
+
iAction,
|
|
741
|
+
Module.UTF8ToString(p3),
|
|
742
|
+
Module.UTF8ToString(p4),
|
|
743
|
+
Module.UTF8ToString(p5),
|
|
744
|
+
Module.UTF8ToString(p6)
|
|
745
|
+
];
|
|
746
|
+
};
|
|
747
|
+
function adapt(f) {
|
|
748
|
+
// return f instanceof AsyncFunction ?
|
|
749
|
+
// (async (_, iAction, p3, p4, p5, p6) => f(...cvtArgs(_, iAction, p3, p4, p5, p6))) :
|
|
750
|
+
// ((_, iAction, p3, p4, p5, p6) => f(...cvtArgs(_, iAction, p3, p4, p5, p6)));
|
|
751
|
+
return ((_, iAction, p3, p4, p5, p6) => f(...cvtArgs(_, iAction, p3, p4, p5, p6)));
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const result = Module.set_authorizer(db, adapt(xAuth), pApp);
|
|
755
|
+
return check('sqlite3_set_authorizer', result, db);
|
|
756
|
+
};;
|
|
757
|
+
|
|
758
|
+
sqlite3.sql = (function() {
|
|
759
|
+
const fname = 'sqlite3_sql';
|
|
760
|
+
const f = Module.cwrap(fname, ...decl('n:s'));
|
|
761
|
+
return function(stmt) {
|
|
762
|
+
verifyStatement(stmt);
|
|
763
|
+
const result = f(stmt);
|
|
764
|
+
return result;
|
|
765
|
+
};
|
|
766
|
+
})();
|
|
767
|
+
|
|
768
|
+
sqlite3.statements = function(db, sql, options = {}) {
|
|
769
|
+
const prepare = Module.cwrap(
|
|
770
|
+
'sqlite3_prepare_v3',
|
|
771
|
+
'number',
|
|
772
|
+
['number', 'number', 'number', 'number', 'number', 'number'],
|
|
773
|
+
// { async: true });
|
|
774
|
+
{ async: false });
|
|
775
|
+
|
|
776
|
+
const stmts = [];
|
|
777
|
+
|
|
778
|
+
// return (async function*() {
|
|
779
|
+
const onFinally = [];
|
|
780
|
+
// try {
|
|
781
|
+
// Encode SQL string to UTF-8.
|
|
782
|
+
const utf8 = textEncoder.encode(sql);
|
|
783
|
+
|
|
784
|
+
// Copy encoded string to WebAssembly memory. The SQLite docs say
|
|
785
|
+
// zero-termination is a minor optimization so add room for that.
|
|
786
|
+
// Also add space for the statement handle and SQL tail pointer.
|
|
787
|
+
const allocSize = utf8.byteLength - (utf8.byteLength % 4) + 12;
|
|
788
|
+
const pzHead = Module._sqlite3_malloc(allocSize);
|
|
789
|
+
const pzEnd = pzHead + utf8.byteLength + 1;
|
|
790
|
+
onFinally.push(() => Module._sqlite3_free(pzHead));
|
|
791
|
+
Module.HEAPU8.set(utf8, pzHead);
|
|
792
|
+
Module.HEAPU8[pzEnd - 1] = 0;
|
|
793
|
+
|
|
794
|
+
// Use extra space for the statement handle and SQL tail pointer.
|
|
795
|
+
const pStmt = pzHead + allocSize - 8;
|
|
796
|
+
const pzTail = pzHead + allocSize - 4;
|
|
797
|
+
|
|
798
|
+
// Ensure that statement handles are not leaked.
|
|
799
|
+
let stmt;
|
|
800
|
+
function maybeFinalize() {
|
|
801
|
+
if (stmt && !options.unscoped) {
|
|
802
|
+
sqlite3.finalize(stmt);
|
|
803
|
+
}
|
|
804
|
+
stmt = 0;
|
|
805
|
+
}
|
|
806
|
+
onFinally.push(maybeFinalize);
|
|
807
|
+
|
|
808
|
+
// Loop over statements.
|
|
809
|
+
Module.setValue(pzTail, pzHead, '*');
|
|
810
|
+
do {
|
|
811
|
+
// Reclaim resources for the previous iteration.
|
|
812
|
+
maybeFinalize();
|
|
813
|
+
|
|
814
|
+
// Call sqlite3_prepare_v3() for the next statement.
|
|
815
|
+
// Allow retry operations.
|
|
816
|
+
const zTail = Module.getValue(pzTail, '*');
|
|
817
|
+
const rc = prepare(
|
|
818
|
+
db,
|
|
819
|
+
zTail,
|
|
820
|
+
pzEnd - pzTail,
|
|
821
|
+
options.flags || 0,
|
|
822
|
+
pStmt,
|
|
823
|
+
pzTail);
|
|
824
|
+
|
|
825
|
+
if (rc !== SQLite.SQLITE_OK) {
|
|
826
|
+
check('sqlite3_prepare_v3', rc, db);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
stmt = Module.getValue(pStmt, '*');
|
|
830
|
+
if (stmt) {
|
|
831
|
+
mapStmtToDB.set(stmt, db);
|
|
832
|
+
// yield stmt;
|
|
833
|
+
stmts.push(stmt);
|
|
834
|
+
}
|
|
835
|
+
} while (stmt);
|
|
836
|
+
// } finally {
|
|
837
|
+
// while (onFinally.length) {
|
|
838
|
+
// onFinally.pop()();
|
|
839
|
+
// }
|
|
840
|
+
// }
|
|
841
|
+
|
|
842
|
+
return stmts;
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
sqlite3.step = (function() {
|
|
846
|
+
const fname = 'sqlite3_step';
|
|
847
|
+
const f = Module.cwrap(fname, ...decl('n:n'), { async });
|
|
848
|
+
// return async function(stmt) {
|
|
849
|
+
return function(stmt) {
|
|
850
|
+
verifyStatement(stmt);
|
|
851
|
+
|
|
852
|
+
// Allow retry operations.
|
|
853
|
+
// const rc = await retry(() => f(stmt));
|
|
854
|
+
const rc = f(stmt);
|
|
855
|
+
|
|
856
|
+
return check(fname, rc, mapStmtToDB.get(stmt), [SQLite.SQLITE_ROW, SQLite.SQLITE_DONE]);
|
|
857
|
+
};
|
|
858
|
+
})();
|
|
859
|
+
|
|
860
|
+
sqlite3.commit_hook = function(db, xCommitHook) {
|
|
861
|
+
verifyDatabase(db);
|
|
862
|
+
Module.commit_hook(db, xCommitHook);
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
sqlite3.update_hook = function(db, xUpdateHook) {
|
|
866
|
+
verifyDatabase(db);
|
|
867
|
+
|
|
868
|
+
// Convert SQLite callback arguments to JavaScript-friendly arguments.
|
|
869
|
+
function cvtArgs(iUpdateType, dbName, tblName, lo32, hi32) {
|
|
870
|
+
return [
|
|
871
|
+
iUpdateType,
|
|
872
|
+
Module.UTF8ToString(dbName),
|
|
873
|
+
Module.UTF8ToString(tblName),
|
|
874
|
+
cvt32x2ToBigInt(lo32, hi32)
|
|
875
|
+
];
|
|
876
|
+
};
|
|
877
|
+
function adapt(f) {
|
|
878
|
+
// return f instanceof AsyncFunction ?
|
|
879
|
+
// (async (iUpdateType, dbName, tblName, lo32, hi32) => f(...cvtArgs(iUpdateType, dbName, tblName, lo32, hi32))) :
|
|
880
|
+
// ((iUpdateType, dbName, tblName, lo32, hi32) => f(...cvtArgs(iUpdateType, dbName, tblName, lo32, hi32)));
|
|
881
|
+
return ((iUpdateType, dbName, tblName, lo32, hi32) => f(...cvtArgs(iUpdateType, dbName, tblName, lo32, hi32)));
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
Module.update_hook(db, adapt(xUpdateHook));
|
|
885
|
+
};;
|
|
886
|
+
|
|
887
|
+
// Session extension bindings
|
|
888
|
+
sqlite3.session_create = (function() {
|
|
889
|
+
const fname = 'sqlite3session_create';
|
|
890
|
+
const f = Module.cwrap(fname, ...decl('nsn:n'));
|
|
891
|
+
return function(db, zDb) {
|
|
892
|
+
verifyDatabase(db);
|
|
893
|
+
const ppSession = Module._malloc(4);
|
|
894
|
+
const result = f(db, zDb, ppSession);
|
|
895
|
+
|
|
896
|
+
if (result !== SQLite.SQLITE_OK) {
|
|
897
|
+
check(fname, result, db);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
const pSession = Module.getValue(ppSession, 'i32');
|
|
901
|
+
return pSession;
|
|
902
|
+
};
|
|
903
|
+
})();
|
|
904
|
+
|
|
905
|
+
sqlite3.session_attach = (function() {
|
|
906
|
+
const fname = 'sqlite3session_attach';
|
|
907
|
+
const f = Module.cwrap(fname, ...decl('ns:n'));
|
|
908
|
+
return function(pSession, zTab) {
|
|
909
|
+
if (typeof pSession !== 'number') {
|
|
910
|
+
throw new SQLiteError('Invalid session object', SQLite.SQLITE_MISUSE);
|
|
911
|
+
}
|
|
912
|
+
const result = f(pSession, zTab);
|
|
913
|
+
return check(fname, result);
|
|
914
|
+
};
|
|
915
|
+
})();
|
|
916
|
+
|
|
917
|
+
sqlite3.session_enable = (function() {
|
|
918
|
+
const fname = 'sqlite3session_enable';
|
|
919
|
+
const f = Module.cwrap(fname, ...decl('nn:n'));
|
|
920
|
+
return function(pSession, enableBool) {
|
|
921
|
+
const enable = enableBool ? 1 : 0;
|
|
922
|
+
if (typeof pSession !== 'number') {
|
|
923
|
+
throw new SQLiteError('Invalid session object', SQLite.SQLITE_MISUSE);
|
|
924
|
+
}
|
|
925
|
+
const result = f(pSession, enable);
|
|
926
|
+
if (result !== enable) {
|
|
927
|
+
throw new SQLiteError('Failed to enable session', SQLite.SQLITE_MISUSE);
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
})();
|
|
931
|
+
|
|
932
|
+
sqlite3.session_changeset = (function() {
|
|
933
|
+
const fname = 'sqlite3session_changeset';
|
|
934
|
+
const f = Module.cwrap(fname, ...decl('nnn:n'));
|
|
935
|
+
return function(pSession) {
|
|
936
|
+
if (typeof pSession !== 'number') {
|
|
937
|
+
throw new SQLiteError('Invalid session object', SQLite.SQLITE_MISUSE);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// Allocate memory for the size (int) and the changeset pointer (void*)
|
|
941
|
+
const sizePtr = Module._malloc(4);
|
|
942
|
+
const changesetPtrPtr = Module._malloc(4);
|
|
943
|
+
|
|
944
|
+
try {
|
|
945
|
+
const result = f(pSession, sizePtr, changesetPtrPtr);
|
|
946
|
+
if (result === SQLite.SQLITE_OK) {
|
|
947
|
+
// Get the size of the changeset
|
|
948
|
+
const size = Module.getValue(sizePtr, 'i32');
|
|
949
|
+
// Get the pointer to the changeset
|
|
950
|
+
const changesetPtr = Module.getValue(changesetPtrPtr, 'i32');
|
|
951
|
+
|
|
952
|
+
// Ensure the pointer is valid before accessing memory
|
|
953
|
+
if (changesetPtr === 0) {
|
|
954
|
+
return {
|
|
955
|
+
result: result,
|
|
956
|
+
size: 0,
|
|
957
|
+
changeset: null
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// Copy the changeset data
|
|
962
|
+
const changeset = new Uint8Array(Module.HEAPU8.subarray(changesetPtr, changesetPtr + size));
|
|
963
|
+
|
|
964
|
+
// Free the allocated changeset memory
|
|
965
|
+
Module._sqlite3_free(changesetPtr);
|
|
966
|
+
|
|
967
|
+
// Return a copy of the changeset
|
|
968
|
+
return {
|
|
969
|
+
result: result,
|
|
970
|
+
size: size,
|
|
971
|
+
changeset: changeset
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
return check(fname, result);
|
|
975
|
+
} finally {
|
|
976
|
+
// Free the allocated memory
|
|
977
|
+
Module._free(sizePtr);
|
|
978
|
+
Module._free(changesetPtrPtr);
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
})();
|
|
982
|
+
|
|
983
|
+
sqlite3.session_delete = (function() {
|
|
984
|
+
const fname = 'sqlite3session_delete';
|
|
985
|
+
const f = Module.cwrap(fname, ...decl('n:v'));
|
|
986
|
+
return function(pSession) {
|
|
987
|
+
if (typeof pSession !== 'number') {
|
|
988
|
+
throw new SQLiteError('Invalid session object', SQLite.SQLITE_MISUSE);
|
|
989
|
+
}
|
|
990
|
+
const result = f(pSession);
|
|
991
|
+
return result;
|
|
992
|
+
};
|
|
993
|
+
})();
|
|
994
|
+
|
|
995
|
+
sqlite3.changeset_start = (function() {
|
|
996
|
+
const fname = 'sqlite3changeset_start';
|
|
997
|
+
const f = Module.cwrap(fname, ...decl('nnn:n'));
|
|
998
|
+
return function(changesetData) {
|
|
999
|
+
// Allocate memory for the input changeset data
|
|
1000
|
+
const inPtr = Module._sqlite3_malloc(changesetData.length);
|
|
1001
|
+
Module.HEAPU8.subarray(inPtr).set(changesetData);
|
|
1002
|
+
|
|
1003
|
+
// Allocate memory for the changeset iterator pointer
|
|
1004
|
+
const ppIter = Module._malloc(4);
|
|
1005
|
+
|
|
1006
|
+
try {
|
|
1007
|
+
// Call the wrapped C function
|
|
1008
|
+
const result = f(ppIter, changesetData.length, inPtr);
|
|
1009
|
+
|
|
1010
|
+
if (result !== SQLite.SQLITE_OK) {
|
|
1011
|
+
check(fname, result); // Handle errors appropriately
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// Retrieve the changeset iterator handle
|
|
1015
|
+
const pIter = Module.getValue(ppIter, 'i32');
|
|
1016
|
+
|
|
1017
|
+
return pIter;
|
|
1018
|
+
} finally {
|
|
1019
|
+
// Free allocated memory
|
|
1020
|
+
Module._sqlite3_free(inPtr);
|
|
1021
|
+
Module._free(ppIter);
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
})();
|
|
1025
|
+
|
|
1026
|
+
sqlite3.changeset_finalize = (function() {
|
|
1027
|
+
const fname = 'sqlite3changeset_finalize';
|
|
1028
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
1029
|
+
return function(pIter) {
|
|
1030
|
+
const result = f(pIter);
|
|
1031
|
+
return result;
|
|
1032
|
+
};
|
|
1033
|
+
})();
|
|
1034
|
+
|
|
1035
|
+
sqlite3.changeset_invert = (function() {
|
|
1036
|
+
const fname = 'sqlite3changeset_invert';
|
|
1037
|
+
const f = Module.cwrap(fname, ...decl('nn:nn'));
|
|
1038
|
+
return function(changesetData) {
|
|
1039
|
+
// Allocate memory for the input changeset data
|
|
1040
|
+
const inPtr = Module._sqlite3_malloc(changesetData.length);
|
|
1041
|
+
Module.HEAPU8.subarray(inPtr).set(changesetData);
|
|
1042
|
+
|
|
1043
|
+
// Allocate memory for the output changeset length and pointer
|
|
1044
|
+
const outLengthPtr = Module._malloc(4);
|
|
1045
|
+
const outPtrPtr = Module._malloc(4);
|
|
1046
|
+
|
|
1047
|
+
// Call the wrapped C function
|
|
1048
|
+
const result = f(changesetData.length, inPtr, outLengthPtr, outPtrPtr);
|
|
1049
|
+
|
|
1050
|
+
if (result !== SQLite.SQLITE_OK) {
|
|
1051
|
+
check(fname, result); // Handle errors appropriately
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// Retrieve the size and pointer of the inverted changeset
|
|
1055
|
+
const outLength = Module.getValue(outLengthPtr, 'i32');
|
|
1056
|
+
const changesetOutPtr = Module.getValue(outPtrPtr, 'i32');
|
|
1057
|
+
|
|
1058
|
+
// Copy the inverted changeset data
|
|
1059
|
+
const changesetOut = new Uint8Array(Module.HEAPU8.buffer, changesetOutPtr, outLength).slice();
|
|
1060
|
+
|
|
1061
|
+
// Free allocated memory
|
|
1062
|
+
Module._sqlite3_free(inPtr);
|
|
1063
|
+
|
|
1064
|
+
// TODO investigate why freeing these pointers causes a crash
|
|
1065
|
+
// RuntimeError: Out of bounds memory access (evaluating 'Module._sqlite3_free(outLengthPtr)')
|
|
1066
|
+
// Repro: https://gist.github.com/schickling/08b10b6fda8583601e586cb0bea333ce
|
|
1067
|
+
|
|
1068
|
+
// Module._sqlite3_free(outLengthPtr);
|
|
1069
|
+
// Module._sqlite3_free(outPtrPtr);
|
|
1070
|
+
|
|
1071
|
+
Module._sqlite3_free(changesetOutPtr);
|
|
1072
|
+
|
|
1073
|
+
return changesetOut;
|
|
1074
|
+
};
|
|
1075
|
+
})();
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* Convenience function to get an inverted changeset from a session
|
|
1079
|
+
* without having to call sqlite3session_changeset() and then sqlite3changeset_invert().
|
|
1080
|
+
* It's more efficient as it's reusing the same memory allocation for the changeset.
|
|
1081
|
+
*/
|
|
1082
|
+
sqlite3.session_changeset_inverted = (function() {
|
|
1083
|
+
const fnameChangeset = 'sqlite3session_changeset';
|
|
1084
|
+
const fChangeset = Module.cwrap(fnameChangeset, ...decl('nnn:n'));
|
|
1085
|
+
const fnameInvert = 'sqlite3changeset_invert';
|
|
1086
|
+
const fInvert = Module.cwrap(fnameInvert, ...decl('nn:nn'));
|
|
1087
|
+
return function(pSession) {
|
|
1088
|
+
if (typeof pSession !== 'number') {
|
|
1089
|
+
throw new SQLiteError('Invalid session object', SQLite.SQLITE_MISUSE);
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// Allocate memory for the size (int) and the changeset pointer (void*)
|
|
1093
|
+
const sizePtr = Module._malloc(4);
|
|
1094
|
+
const changesetPtrPtr = Module._malloc(4);
|
|
1095
|
+
|
|
1096
|
+
// Allocate memory for the size (int) and the inverted changeset pointer (void*)
|
|
1097
|
+
const sizePtrInvert = Module._malloc(4);
|
|
1098
|
+
const changesetPtrPtrInvert = Module._malloc(4);
|
|
1099
|
+
|
|
1100
|
+
try {
|
|
1101
|
+
const changesetResult = fChangeset(pSession, sizePtr, changesetPtrPtr);
|
|
1102
|
+
if (changesetResult !== SQLite.SQLITE_OK) {
|
|
1103
|
+
return check(fnameChangeset, changesetResult);
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// Get the size of the changeset
|
|
1107
|
+
const size = Module.getValue(sizePtr, 'i32');
|
|
1108
|
+
// Get the pointer to the changeset
|
|
1109
|
+
const changesetPtr = Module.getValue(changesetPtrPtr, 'i32');
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
const invertedResult = fInvert(size, changesetPtr, sizePtrInvert, changesetPtrPtrInvert);
|
|
1113
|
+
|
|
1114
|
+
if (invertedResult !== SQLite.SQLITE_OK) {
|
|
1115
|
+
return check(fnameInvert, invertedResult);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
// Get the size of the changeset
|
|
1119
|
+
const sizeInvert = Module.getValue(sizePtrInvert, 'i32');
|
|
1120
|
+
// Get the pointer to the changeset
|
|
1121
|
+
const changesetPtrInvert = Module.getValue(changesetPtrPtrInvert, 'i32');
|
|
1122
|
+
|
|
1123
|
+
// Copy the changeset data
|
|
1124
|
+
const changesetInvert = new Uint8Array(Module.HEAPU8.buffer, changesetPtrInvert, sizeInvert);
|
|
1125
|
+
|
|
1126
|
+
Module._sqlite3_free(changesetPtr);
|
|
1127
|
+
Module._sqlite3_free(changesetPtrInvert)
|
|
1128
|
+
|
|
1129
|
+
// Return a copy of the changeset
|
|
1130
|
+
return {
|
|
1131
|
+
result: changesetResult,
|
|
1132
|
+
size: size,
|
|
1133
|
+
changeset: new Uint8Array(changesetInvert)
|
|
1134
|
+
};
|
|
1135
|
+
} finally {
|
|
1136
|
+
// Free the allocated memory
|
|
1137
|
+
Module._free(sizePtr);
|
|
1138
|
+
Module._free(changesetPtrPtr);
|
|
1139
|
+
Module._free(sizePtrInvert);
|
|
1140
|
+
Module._free(changesetPtrPtrInvert);
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
};
|
|
1144
|
+
})();
|
|
1145
|
+
|
|
1146
|
+
sqlite3.changeset_apply = (function() {
|
|
1147
|
+
const fname = 'sqlite3changeset_apply';
|
|
1148
|
+
const f = Module.cwrap(fname, ...decl('nnnnnn:n'));
|
|
1149
|
+
return function(db, changesetData, options) {
|
|
1150
|
+
/*
|
|
1151
|
+
int sqlite3changeset_apply(
|
|
1152
|
+
sqlite3 *db, Apply change to "main" db of this handle
|
|
1153
|
+
int nChangeset, Size of changeset in bytes
|
|
1154
|
+
void *pChangeset, Changeset blob
|
|
1155
|
+
int(*xFilter)(
|
|
1156
|
+
void *pCtx, Copy of sixth arg to _apply()
|
|
1157
|
+
const char *zTab Table name
|
|
1158
|
+
),
|
|
1159
|
+
int(*xConflict)(
|
|
1160
|
+
void *pCtx, Copy of sixth arg to _apply()
|
|
1161
|
+
int eConflict, DATA, MISSING, CONFLICT, CONSTRAINT
|
|
1162
|
+
sqlite3_changeset_iter *p Handle describing change and conflict
|
|
1163
|
+
),
|
|
1164
|
+
void *pCtx First argument passed to xConflict
|
|
1165
|
+
);
|
|
1166
|
+
*/
|
|
1167
|
+
const inPtr = Module._sqlite3_malloc(changesetData.length);
|
|
1168
|
+
Module.HEAPU8.subarray(inPtr).set(changesetData);
|
|
1169
|
+
|
|
1170
|
+
// https://sqlite.org/session/c_changeset_abort.html
|
|
1171
|
+
const SQLITE_CHANGESET_REPLACE = 1
|
|
1172
|
+
const onConflict = () => {
|
|
1173
|
+
return SQLITE_CHANGESET_REPLACE;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
const result = f(db, changesetData.length, inPtr, null, onConflict, null);
|
|
1177
|
+
|
|
1178
|
+
Module._sqlite3_free(inPtr);
|
|
1179
|
+
|
|
1180
|
+
if (result !== SQLite.SQLITE_OK) {
|
|
1181
|
+
check(fname, result);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
return result;
|
|
1185
|
+
}
|
|
1186
|
+
})();
|
|
1187
|
+
|
|
1188
|
+
// Session extension bindings end
|
|
1189
|
+
|
|
1190
|
+
sqlite3.value = function(pValue) {
|
|
1191
|
+
const type = sqlite3.value_type(pValue);
|
|
1192
|
+
switch (type) {
|
|
1193
|
+
case SQLite.SQLITE_BLOB:
|
|
1194
|
+
return sqlite3.value_blob(pValue);
|
|
1195
|
+
case SQLite.SQLITE_FLOAT:
|
|
1196
|
+
return sqlite3.value_double(pValue);
|
|
1197
|
+
case SQLite.SQLITE_INTEGER:
|
|
1198
|
+
const lo32 = sqlite3.value_int(pValue);
|
|
1199
|
+
const hi32 = Module.getTempRet0();
|
|
1200
|
+
return cvt32x2AsSafe(lo32, hi32);
|
|
1201
|
+
case SQLite.SQLITE_NULL:
|
|
1202
|
+
return null;
|
|
1203
|
+
case SQLite.SQLITE_TEXT:
|
|
1204
|
+
return sqlite3.value_text(pValue);
|
|
1205
|
+
default:
|
|
1206
|
+
throw new SQLiteError('unknown type', type);
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
|
|
1210
|
+
sqlite3.value_blob = (function() {
|
|
1211
|
+
const fname = 'sqlite3_value_blob';
|
|
1212
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
1213
|
+
return function(pValue) {
|
|
1214
|
+
const nBytes = sqlite3.value_bytes(pValue);
|
|
1215
|
+
const address = f(pValue);
|
|
1216
|
+
const result = Module.HEAPU8.subarray(address, address + nBytes);
|
|
1217
|
+
return result;
|
|
1218
|
+
};
|
|
1219
|
+
})();
|
|
1220
|
+
|
|
1221
|
+
sqlite3.value_bytes = (function() {
|
|
1222
|
+
const fname = 'sqlite3_value_bytes';
|
|
1223
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
1224
|
+
return function(pValue) {
|
|
1225
|
+
const result = f(pValue);
|
|
1226
|
+
return result;
|
|
1227
|
+
};
|
|
1228
|
+
})();
|
|
1229
|
+
|
|
1230
|
+
sqlite3.value_double = (function() {
|
|
1231
|
+
const fname = 'sqlite3_value_double';
|
|
1232
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
1233
|
+
return function(pValue) {
|
|
1234
|
+
const result = f(pValue);
|
|
1235
|
+
return result;
|
|
1236
|
+
};
|
|
1237
|
+
})();
|
|
1238
|
+
|
|
1239
|
+
sqlite3.value_int = (function() {
|
|
1240
|
+
const fname = 'sqlite3_value_int64';
|
|
1241
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
1242
|
+
return function(pValue) {
|
|
1243
|
+
const result = f(pValue);
|
|
1244
|
+
return result;
|
|
1245
|
+
};
|
|
1246
|
+
})();
|
|
1247
|
+
|
|
1248
|
+
sqlite3.value_int64 = (function() {
|
|
1249
|
+
const fname = 'sqlite3_value_int64';
|
|
1250
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
1251
|
+
return function(pValue) {
|
|
1252
|
+
const lo32 = f(pValue);
|
|
1253
|
+
const hi32 = Module.getTempRet0();
|
|
1254
|
+
const result = cvt32x2ToBigInt(lo32, hi32);
|
|
1255
|
+
return result;
|
|
1256
|
+
};
|
|
1257
|
+
})();
|
|
1258
|
+
|
|
1259
|
+
sqlite3.value_text = (function() {
|
|
1260
|
+
const fname = 'sqlite3_value_text';
|
|
1261
|
+
const f = Module.cwrap(fname, ...decl('n:s'));
|
|
1262
|
+
return function(pValue) {
|
|
1263
|
+
const result = f(pValue);
|
|
1264
|
+
return result;
|
|
1265
|
+
};
|
|
1266
|
+
})();
|
|
1267
|
+
|
|
1268
|
+
sqlite3.value_type = (function() {
|
|
1269
|
+
const fname = 'sqlite3_value_type';
|
|
1270
|
+
const f = Module.cwrap(fname, ...decl('n:n'));
|
|
1271
|
+
return function(pValue) {
|
|
1272
|
+
const result = f(pValue);
|
|
1273
|
+
return result;
|
|
1274
|
+
};
|
|
1275
|
+
})();
|
|
1276
|
+
|
|
1277
|
+
const registeredVfs = new Set();
|
|
1278
|
+
|
|
1279
|
+
sqlite3.vfs_register = function(vfs, makeDefault) {
|
|
1280
|
+
if (registeredVfs.has(vfs.name)) return
|
|
1281
|
+
const result = Module.vfs_register(vfs, makeDefault);
|
|
1282
|
+
const res = check('sqlite3_vfs_register', result);
|
|
1283
|
+
registeredVfs.add(vfs.name);
|
|
1284
|
+
return res
|
|
1285
|
+
};
|
|
1286
|
+
|
|
1287
|
+
sqlite3.vfs_registered = registeredVfs;
|
|
1288
|
+
|
|
1289
|
+
function check(fname, result, db = null, allowed = [SQLite.SQLITE_OK]) {
|
|
1290
|
+
if (allowed.includes(result)) return result;
|
|
1291
|
+
const message = db ?
|
|
1292
|
+
Module.ccall('sqlite3_errmsg', 'string', ['number'], [db]) :
|
|
1293
|
+
fname;
|
|
1294
|
+
throw new SQLiteError(message, result);
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// This function is used to automatically retry failed calls that
|
|
1298
|
+
// have pending retry operations that should allow the retry to
|
|
1299
|
+
// succeed.
|
|
1300
|
+
async function retry(f) {
|
|
1301
|
+
let rc;
|
|
1302
|
+
do {
|
|
1303
|
+
// Wait for all pending retry operations to complete. This is
|
|
1304
|
+
// normally empty on the first loop iteration.
|
|
1305
|
+
if (Module.retryOps.length) {
|
|
1306
|
+
await Promise.all(Module.retryOps);
|
|
1307
|
+
Module.retryOps = [];
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
rc = await f();
|
|
1311
|
+
|
|
1312
|
+
// Retry on failure with new pending retry operations.
|
|
1313
|
+
} while (rc && Module.retryOps.length);
|
|
1314
|
+
return rc;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
return sqlite3;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
// Helper function to use a more compact signature specification.
|
|
1321
|
+
function decl(s) {
|
|
1322
|
+
const result = [];
|
|
1323
|
+
const m = s.match(/([ns@]*):([nsv@])/);
|
|
1324
|
+
switch (m[2]) {
|
|
1325
|
+
case 'n': result.push('number'); break;
|
|
1326
|
+
case 's': result.push('string'); break;
|
|
1327
|
+
case 'v': result.push(null); break;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
const args = [];
|
|
1331
|
+
for (let c of m[1]) {
|
|
1332
|
+
switch (c) {
|
|
1333
|
+
case 'n': args.push('number'); break;
|
|
1334
|
+
case 's': args.push('string'); break;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
result.push(args);
|
|
1338
|
+
return result;
|
|
1339
|
+
}
|