4 The author disclaims copyright to this source code. In place of a
5 legal notice, here is a blessing:
7 * May you do good and not evil.
8 * May you find forgiveness for yourself and forgive others.
9 * May you share freely, never taking more than you give.
11 ***********************************************************************
13 This file glues together disparate pieces of JS which are loaded in
14 previous steps of the sqlite3-api.js bootstrapping process:
15 sqlite3-api-prologue.js, whwasmutil.js, and jaccwabyt.js. It
16 initializes the main API pieces so that the downstream components
17 (e.g. sqlite3-api-oo1.js) have all of the infrastructure that they
20 globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
22 const toss = (...args)=>{throw new Error(args.join(' '))};
23 const toss3 = sqlite3.SQLite3Error.toss;
24 const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util;
25 globalThis.WhWasmUtilInstaller(wasm);
26 delete globalThis.WhWasmUtilInstaller;
30 Please keep this block around as a maintenance reminder
31 that we cannot rely on this type of check.
33 This block fails on Safari, per a report at
34 https://sqlite.org/forum/forumpost/e5b20e1feb.
36 It turns out that what Safari serves from the indirect function
37 table (e.g. wasm.functionEntry(X)) is anonymous functions which
38 wrap the WASM functions, rather than returning the WASM
39 functions themselves. That means comparison of such functions
40 is useless for determining whether or not we have a specific
41 function from wasm.exports. i.e. if function X is indirection
42 function table entry N then wasm.exports.X is not equal to
43 wasm.functionEntry(N) in Safari, despite being so in the other
47 Find a mapping for SQLITE_WASM_DEALLOC, which the API
48 guarantees is a WASM pointer to the same underlying function as
49 wasm.dealloc() (noting that wasm.dealloc() is permitted to be a
50 JS wrapper around the WASM function). There is unfortunately no
51 O(1) algorithm for finding this pointer: we have to walk the
52 WASM indirect function table to find it. However, experience
53 indicates that that particular function is always very close to
54 the front of the table (it's been entry #3 in all relevant
57 const dealloc = wasm.exports[sqlite3.config.deallocExportName];
58 const nFunc = wasm.functionTable().length;
60 for(i = 0; i < nFunc; ++i){
61 const e = wasm.functionEntry(i);
63 capi.SQLITE_WASM_DEALLOC = i;
67 if(dealloc !== wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)){
68 toss("Internal error: cannot find function pointer for SQLITE_WASM_DEALLOC.");
73 Signatures for the WASM-exported C-side functions. Each entry
74 is an array with 2+ elements:
77 "result type" (wasm.xWrap() syntax),
78 [arg types in xWrap() syntax]
79 // ^^^ this needn't strictly be an array: it can be subsequent
80 // elements instead: [x,y,z] is equivalent to x,y,z
83 Note that support for the API-specific data types in the
84 result/argument type strings gets plugged in at a later phase in
85 the API initialization process.
87 wasm.bindingSignatures = [
88 // Please keep these sorted by function name!
89 ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
90 /* sqlite3_auto_extension() has a hand-written binding. */
91 /* sqlite3_bind_blob() and sqlite3_bind_text() have hand-written
92 bindings to permit more flexible inputs. */
93 ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
94 ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
95 ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
96 ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"],
97 ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
98 ["sqlite3_bind_pointer", "int",
99 "sqlite3_stmt*", "int", "*", "string:static", "*"],
100 ["sqlite3_busy_handler","int", [
102 new wasm.xWrap.FuncPtrAdapter({
104 contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
108 ["sqlite3_busy_timeout","int", "sqlite3*", "int"],
109 /* sqlite3_cancel_auto_extension() has a hand-written binding. */
110 /* sqlite3_close_v2() is implemented by hand to perform some
112 ["sqlite3_changes", "int", "sqlite3*"],
113 ["sqlite3_clear_bindings","int", "sqlite3_stmt*"],
114 ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"/*=>v(ppis)*/],
115 ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"],
116 ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"],
117 ["sqlite3_column_count", "int", "sqlite3_stmt*"],
118 ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"],
119 ["sqlite3_column_int","int", "sqlite3_stmt*", "int"],
120 ["sqlite3_column_name","string", "sqlite3_stmt*", "int"],
121 ["sqlite3_column_text","string", "sqlite3_stmt*", "int"],
122 ["sqlite3_column_type","int", "sqlite3_stmt*", "int"],
123 ["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"],
124 ["sqlite3_commit_hook", "void*", [
126 new wasm.xWrap.FuncPtrAdapter({
127 name: 'sqlite3_commit_hook',
129 contextKey: (argv)=>argv[0/* sqlite3* */]
133 ["sqlite3_compileoption_get", "string", "int"],
134 ["sqlite3_compileoption_used", "int", "string"],
135 ["sqlite3_complete", "int", "string:flexible"],
136 ["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"],
138 /* sqlite3_create_function(), sqlite3_create_function_v2(), and
139 sqlite3_create_window_function() use hand-written bindings to
140 simplify handling of their function-type arguments. */
141 /* sqlite3_create_collation() and sqlite3_create_collation_v2()
142 use hand-written bindings to simplify passing of the callback
144 ["sqlite3_create_collation", "int",
145 "sqlite3*", "string", "int",//SQLITE_UTF8 is the only legal value
147 ["sqlite3_create_collation_v2", "int",
148 "sqlite3*", "string", "int",//SQLITE_UTF8 is the only legal value
151 ["sqlite3_data_count", "int", "sqlite3_stmt*"],
152 ["sqlite3_db_filename", "string", "sqlite3*", "string"],
153 ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"],
154 ["sqlite3_db_name", "string", "sqlite3*", "int"],
155 ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"],
156 ["sqlite3_errcode", "int", "sqlite3*"],
157 ["sqlite3_errmsg", "string", "sqlite3*"],
158 ["sqlite3_error_offset", "int", "sqlite3*"],
159 ["sqlite3_errstr", "string", "int"],
160 ["sqlite3_exec", "int", [
161 "sqlite3*", "string:flexible",
162 new wasm.xWrap.FuncPtrAdapter({
163 signature: 'i(pipp)',
164 bindScope: 'transient',
165 callProxy: (callback)=>{
167 return (pVoid, nCols, pColVals, pColNames)=>{
169 const aVals = wasm.cArgvToJs(nCols, pColVals);
170 if(!aNames) aNames = wasm.cArgvToJs(nCols, pColNames);
171 return callback(aVals, aNames) | 0;
173 /* If we set the db error state here, the higher-level
174 exec() call replaces it with its own, so we have no way
175 of reporting the exception message except the console. We
176 must not propagate exceptions through the C API. Though
177 we make an effort to report OOM here, sqlite3_exec()
178 translates that into SQLITE_ABORT as well. */
179 return e.resultCode || capi.SQLITE_ERROR;
186 ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"],
187 ["sqlite3_extended_errcode", "int", "sqlite3*"],
188 ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"],
189 ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"],
190 ["sqlite3_finalize", "int", "sqlite3_stmt*"],
191 ["sqlite3_free", undefined,"*"],
192 ["sqlite3_get_autocommit", "int", "sqlite3*"],
193 ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"],
194 ["sqlite3_initialize", undefined],
195 /*["sqlite3_interrupt", undefined, "sqlite3*"
196 ^^^ we cannot actually currently support this because JS is
197 single-threaded and we don't have a portable way to access a DB
198 from 2 SharedWorkers concurrently. ],*/
199 ["sqlite3_keyword_count", "int"],
200 ["sqlite3_keyword_name", "int", ["int", "**", "*"]],
201 ["sqlite3_keyword_check", "int", ["string", "int"]],
202 ["sqlite3_libversion", "string"],
203 ["sqlite3_libversion_number", "int"],
204 ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]],
205 ["sqlite3_malloc", "*","int"],
206 ["sqlite3_open", "int", "string", "*"],
207 ["sqlite3_open_v2", "int", "string", "*", "int", "string"],
208 /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled
209 separately due to us requiring two different sets of semantics
210 for those, depending on how their SQL argument is provided. */
211 /* sqlite3_randomness() uses a hand-written wrapper to extend
212 the range of supported argument types. */
213 ["sqlite3_progress_handler", undefined, [
214 "sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({
215 name: 'xProgressHandler',
217 bindScope: 'context',
218 contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
221 ["sqlite3_realloc", "*","*","int"],
222 ["sqlite3_reset", "int", "sqlite3_stmt*"],
223 /* sqlite3_reset_auto_extension() has a hand-written binding. */
224 ["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"],
225 ["sqlite3_result_double", undefined, "sqlite3_context*", "f64"],
226 ["sqlite3_result_error", undefined, "sqlite3_context*", "string", "int"],
227 ["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"],
228 ["sqlite3_result_error_nomem", undefined, "sqlite3_context*"],
229 ["sqlite3_result_error_toobig", undefined, "sqlite3_context*"],
230 ["sqlite3_result_int", undefined, "sqlite3_context*", "int"],
231 ["sqlite3_result_null", undefined, "sqlite3_context*"],
232 ["sqlite3_result_pointer", undefined,
233 "sqlite3_context*", "*", "string:static", "*"],
234 ["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"],
235 ["sqlite3_result_text", undefined, "sqlite3_context*", "string", "int", "*"],
236 ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"],
237 ["sqlite3_rollback_hook", "void*", [
239 new wasm.xWrap.FuncPtrAdapter({
240 name: 'sqlite3_rollback_hook',
242 contextKey: (argv)=>argv[0/* sqlite3* */]
246 ["sqlite3_set_authorizer", "int", [
248 new wasm.xWrap.FuncPtrAdapter({
249 name: "sqlite3_set_authorizer::xAuth",
250 signature: "i(pi"+"ssss)",
251 contextKey: (argv, argIndex)=>argv[0/*(sqlite3*)*/],
252 callProxy: (callback)=>{
253 return (pV, iCode, s0, s1, s2, s3)=>{
255 s0 = s0 && wasm.cstrToJs(s0); s1 = s1 && wasm.cstrToJs(s1);
256 s2 = s2 && wasm.cstrToJs(s2); s3 = s3 && wasm.cstrToJs(s3);
257 return callback(pV, iCode, s0, s1, s2, s3) || 0;
259 return e.resultCode || capi.SQLITE_ERROR;
266 ["sqlite3_set_auxdata", undefined, [
267 "sqlite3_context*", "int", "*",
268 new wasm.xWrap.FuncPtrAdapter({
269 name: 'xDestroyAuxData',
271 contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
274 ["sqlite3_shutdown", undefined],
275 ["sqlite3_sourceid", "string"],
276 ["sqlite3_sql", "string", "sqlite3_stmt*"],
277 ["sqlite3_status", "int", "int", "*", "*", "int"],
278 ["sqlite3_step", "int", "sqlite3_stmt*"],
279 ["sqlite3_stmt_isexplain", "int", ["sqlite3_stmt*"]],
280 ["sqlite3_stmt_readonly", "int", ["sqlite3_stmt*"]],
281 ["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"],
282 ["sqlite3_strglob", "int", "string","string"],
283 ["sqlite3_stricmp", "int", "string", "string"],
284 ["sqlite3_strlike", "int", "string", "string","int"],
285 ["sqlite3_strnicmp", "int", "string", "string", "int"],
286 ["sqlite3_table_column_metadata", "int",
287 "sqlite3*", "string", "string", "string",
288 "**", "**", "*", "*", "*"],
289 ["sqlite3_total_changes", "int", "sqlite3*"],
290 ["sqlite3_trace_v2", "int", [
292 new wasm.xWrap.FuncPtrAdapter({
293 name: 'sqlite3_trace_v2::callback',
294 signature: 'i(ippp)',
295 contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
299 ["sqlite3_txn_state", "int", ["sqlite3*","string"]],
300 /* Note that sqlite3_uri_...() have very specific requirements for
301 their first C-string arguments, so we cannot perform any value
302 conversion on those. */
303 ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"],
304 ["sqlite3_uri_key", "string", "sqlite3_filename", "int"],
305 ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"],
306 ["sqlite3_user_data","void*", "sqlite3_context*"],
307 ["sqlite3_value_blob", "*", "sqlite3_value*"],
308 ["sqlite3_value_bytes","int", "sqlite3_value*"],
309 ["sqlite3_value_double","f64", "sqlite3_value*"],
310 ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"],
311 ["sqlite3_value_free", undefined, "sqlite3_value*"],
312 ["sqlite3_value_frombind", "int", "sqlite3_value*"],
313 ["sqlite3_value_int","int", "sqlite3_value*"],
314 ["sqlite3_value_nochange", "int", "sqlite3_value*"],
315 ["sqlite3_value_numeric_type", "int", "sqlite3_value*"],
316 ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"],
317 ["sqlite3_value_subtype", "int", "sqlite3_value*"],
318 ["sqlite3_value_text", "string", "sqlite3_value*"],
319 ["sqlite3_value_type", "int", "sqlite3_value*"],
320 ["sqlite3_vfs_find", "*", "string"],
321 ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"],
322 ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"]
323 ]/*wasm.bindingSignatures*/;
325 if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
326 /* ^^^ "the problem" is that this is an option feature and the
327 build-time function-export list does not currently take
328 optional features into account. */
329 wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]);
333 if(wasm.exports.sqlite3_key_v2 instanceof Function){
335 This code is capable of using an SEE build but note that an SEE
336 WASM build is generally incompatible with SEE's license
337 conditions. It is permitted for use internally in organizations
338 which have licensed SEE, but not for public sites because
339 exposing an SEE build of sqlite3.wasm effectively provides all
340 clients with a working copy of the commercial SEE code.
342 wasm.bindingSignatures.push(
343 ["sqlite3_key", "int", "sqlite3*", "string", "int"],
344 ["sqlite3_key_v2","int","sqlite3*","string","*","int"],
345 ["sqlite3_rekey", "int", "sqlite3*", "string", "int"],
346 ["sqlite3_rekey_v2", "int", "sqlite3*", "string", "*", "int"],
347 ["sqlite3_activate_see", undefined, "string"]
353 Functions which require BigInt (int64) support are separated from
354 the others because we need to conditionally bind them or apply
355 dummy impls, depending on the capabilities of the environment.
356 (That said: we never actually build without BigInt support,
357 and such builds are untested.)
359 Note that not all of these functions directly require int64
360 but are only for use with APIs which require int64. For example,
361 the vtab-related functions.
363 wasm.bindingSignatures.int64 = [
364 ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]],
365 ["sqlite3_changes64","i64", ["sqlite3*"]],
366 ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]],
367 ["sqlite3_create_module", "int",
368 ["sqlite3*","string","sqlite3_module*","*"]],
369 ["sqlite3_create_module_v2", "int",
370 ["sqlite3*","string","sqlite3_module*","*","*"]],
371 ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]],
372 ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"]
373 /* Careful! Short version: de/serialize() are problematic because they
374 might use a different allocator than the user for managing the
375 deserialized block. de/serialize() are ONLY safe to use with
376 sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. Because
377 of this, the canonical builds of sqlite3.wasm/js guarantee that
378 sqlite3.wasm.alloc() and friends use those allocators. Custom builds
379 may not guarantee that, however. */,
380 ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]],
381 ["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]],
382 ["sqlite3_malloc64", "*","i64"],
383 ["sqlite3_msize", "i64", "*"],
384 ["sqlite3_overload_function", "int", ["sqlite3*","string","int"]],
385 ["sqlite3_preupdate_blobwrite", "int", "sqlite3*"],
386 ["sqlite3_preupdate_count", "int", "sqlite3*"],
387 ["sqlite3_preupdate_depth", "int", "sqlite3*"],
388 ["sqlite3_preupdate_hook", "*", [
390 new wasm.xWrap.FuncPtrAdapter({
391 name: 'sqlite3_preupdate_hook',
392 signature: "v(ppippjj)",
393 contextKey: (argv)=>argv[0/* sqlite3* */],
394 callProxy: (callback)=>{
395 return (p,db,op,zDb,zTbl,iKey1,iKey2)=>{
396 callback(p, db, op, wasm.cstrToJs(zDb), wasm.cstrToJs(zTbl),
403 ["sqlite3_preupdate_new", "int", ["sqlite3*", "int", "**"]],
404 ["sqlite3_preupdate_old", "int", ["sqlite3*", "int", "**"]],
405 ["sqlite3_realloc64", "*","*", "i64"],
406 ["sqlite3_result_int64", undefined, "*", "i64"],
407 ["sqlite3_result_zeroblob64", "int", "*", "i64"],
408 ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"],
409 ["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]],
410 ["sqlite3_status64", "int", "int", "*", "*", "int"],
411 ["sqlite3_total_changes64", "i64", ["sqlite3*"]],
412 ["sqlite3_update_hook", "*", [
414 new wasm.xWrap.FuncPtrAdapter({
415 name: 'sqlite3_update_hook',
416 signature: "v(iippj)",
417 contextKey: (argv)=>argv[0/* sqlite3* */],
418 callProxy: (callback)=>{
419 return (p,op,z0,z1,rowid)=>{
420 callback(p, op, wasm.cstrToJs(z0), wasm.cstrToJs(z1), rowid);
426 ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]],
427 ["sqlite3_value_int64","i64", "sqlite3_value*"],
428 ["sqlite3_vtab_collation","string","sqlite3_index_info*","int"],
429 ["sqlite3_vtab_distinct","int", "sqlite3_index_info*"],
430 ["sqlite3_vtab_in","int", "sqlite3_index_info*", "int", "int"],
431 ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"],
432 ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"],
433 /*["sqlite3_vtab_config" is variadic and requires a hand-written
435 ["sqlite3_vtab_nochange","int", "sqlite3_context*"],
436 ["sqlite3_vtab_on_conflict","int", "sqlite3*"],
437 ["sqlite3_vtab_rhs_value","int", "sqlite3_index_info*", "int", "**"]
440 // Add session/changeset APIs...
441 if(wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add){
443 FuncPtrAdapter options for session-related callbacks with the
444 native signature "i(ps)". This proxy converts the 2nd argument
445 from a C string to a JS string before passing the arguments on
446 to the client-provided JS callback.
450 callProxy:(callback)=>{
452 try{return callback(p, wasm.cstrToJs(s)) | 0}
453 catch(e){return e.resultCode || capi.SQLITE_ERROR}
458 wasm.bindingSignatures.int64.push(...[
459 ['sqlite3changegroup_add', 'int', ['sqlite3_changegroup*', 'int', 'void*']],
460 ['sqlite3changegroup_add_strm', 'int', [
461 'sqlite3_changegroup*',
462 new wasm.xWrap.FuncPtrAdapter({
463 name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
467 ['sqlite3changegroup_delete', undefined, ['sqlite3_changegroup*']],
468 ['sqlite3changegroup_new', 'int', ['**']],
469 ['sqlite3changegroup_output', 'int', ['sqlite3_changegroup*', 'int*', '**']],
470 ['sqlite3changegroup_output_strm', 'int', [
471 'sqlite3_changegroup*',
472 new wasm.xWrap.FuncPtrAdapter({
473 name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
477 ['sqlite3changeset_apply', 'int', [
478 'sqlite3*', 'int', 'void*',
479 new wasm.xWrap.FuncPtrAdapter({
480 name: 'xFilter', bindScope: 'transient', ...__ipsProxy
482 new wasm.xWrap.FuncPtrAdapter({
483 name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
487 ['sqlite3changeset_apply_strm', 'int', [
489 new wasm.xWrap.FuncPtrAdapter({
490 name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
493 new wasm.xWrap.FuncPtrAdapter({
494 name: 'xFilter', bindScope: 'transient', ...__ipsProxy
496 new wasm.xWrap.FuncPtrAdapter({
497 name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
501 ['sqlite3changeset_apply_v2', 'int', [
502 'sqlite3*', 'int', 'void*',
503 new wasm.xWrap.FuncPtrAdapter({
504 name: 'xFilter', bindScope: 'transient', ...__ipsProxy
506 new wasm.xWrap.FuncPtrAdapter({
507 name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
509 'void*', '**', 'int*', 'int'
512 ['sqlite3changeset_apply_v2_strm', 'int', [
514 new wasm.xWrap.FuncPtrAdapter({
515 name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
518 new wasm.xWrap.FuncPtrAdapter({
519 name: 'xFilter', bindScope: 'transient', ...__ipsProxy
521 new wasm.xWrap.FuncPtrAdapter({
522 name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
524 'void*', '**', 'int*', 'int'
526 ['sqlite3changeset_concat', 'int', ['int','void*', 'int', 'void*', 'int*', '**']],
527 ['sqlite3changeset_concat_strm', 'int', [
528 new wasm.xWrap.FuncPtrAdapter({
529 name: 'xInputA', signature: 'i(ppp)', bindScope: 'transient'
532 new wasm.xWrap.FuncPtrAdapter({
533 name: 'xInputB', signature: 'i(ppp)', bindScope: 'transient'
536 new wasm.xWrap.FuncPtrAdapter({
537 name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
541 ['sqlite3changeset_conflict', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
542 ['sqlite3changeset_finalize', 'int', ['sqlite3_changeset_iter*']],
543 ['sqlite3changeset_fk_conflicts', 'int', ['sqlite3_changeset_iter*', 'int*']],
544 ['sqlite3changeset_invert', 'int', ['int', 'void*', 'int*', '**']],
545 ['sqlite3changeset_invert_strm', 'int', [
546 new wasm.xWrap.FuncPtrAdapter({
547 name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
550 new wasm.xWrap.FuncPtrAdapter({
551 name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
555 ['sqlite3changeset_new', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
556 ['sqlite3changeset_next', 'int', ['sqlite3_changeset_iter*']],
557 ['sqlite3changeset_old', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
558 ['sqlite3changeset_op', 'int', [
559 'sqlite3_changeset_iter*', '**', 'int*', 'int*','int*'
561 ['sqlite3changeset_pk', 'int', ['sqlite3_changeset_iter*', '**', 'int*']],
562 ['sqlite3changeset_start', 'int', ['**', 'int', '*']],
563 ['sqlite3changeset_start_strm', 'int', [
565 new wasm.xWrap.FuncPtrAdapter({
566 name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
570 ['sqlite3changeset_start_v2', 'int', ['**', 'int', '*', 'int']],
571 ['sqlite3changeset_start_v2_strm', 'int', [
573 new wasm.xWrap.FuncPtrAdapter({
574 name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
578 ['sqlite3session_attach', 'int', ['sqlite3_session*', 'string']],
579 ['sqlite3session_changeset', 'int', ['sqlite3_session*', 'int*', '**']],
580 ['sqlite3session_changeset_size', 'i64', ['sqlite3_session*']],
581 ['sqlite3session_changeset_strm', 'int', [
583 new wasm.xWrap.FuncPtrAdapter({
584 name: 'xOutput', signature: 'i(ppp)', bindScope: 'transient'
588 ['sqlite3session_config', 'int', ['int', 'void*']],
589 ['sqlite3session_create', 'int', ['sqlite3*', 'string', '**']],
590 //sqlite3session_delete() is bound manually
591 ['sqlite3session_diff', 'int', ['sqlite3_session*', 'string', 'string', '**']],
592 ['sqlite3session_enable', 'int', ['sqlite3_session*', 'int']],
593 ['sqlite3session_indirect', 'int', ['sqlite3_session*', 'int']],
594 ['sqlite3session_isempty', 'int', ['sqlite3_session*']],
595 ['sqlite3session_memory_used', 'i64', ['sqlite3_session*']],
596 ['sqlite3session_object_config', 'int', ['sqlite3_session*', 'int', 'void*']],
597 ['sqlite3session_patchset', 'int', ['sqlite3_session*', '*', '**']],
598 ['sqlite3session_patchset_strm', 'int', [
600 new wasm.xWrap.FuncPtrAdapter({
601 name: 'xOutput', signature: 'i(ppp)', bindScope: 'transient'
605 ['sqlite3session_table_filter', undefined, [
607 new wasm.xWrap.FuncPtrAdapter({
608 name: 'xFilter', ...__ipsProxy,
609 contextKey: (argv,argIndex)=>argv[0/* (sqlite3_session*) */]
614 }/*session/changeset APIs*/
617 Functions which are intended solely for API-internal use by the
618 WASM components, not client code. These get installed into
619 sqlite3.util. Some of them get exposed to clients via variants
622 2024-01-11: these were renamed, with two underscores in the
623 prefix, to ensure that clients do not accidentally depend on
624 them. They have always been documented as internal-use-only, so
625 no clients "should" be depending on the old names.
627 wasm.bindingSignatures.wasmInternal = [
628 ["sqlite3__wasm_db_reset", "int", "sqlite3*"],
629 ["sqlite3__wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
630 [/* DO NOT USE. This is deprecated since 2023-08-11 because it can
631 trigger assert() in debug builds when used with file sizes
632 which are not sizes to a multiple of a valid db page size. */
633 "sqlite3__wasm_vfs_create_file", "int", "sqlite3_vfs*","string","*", "int"
635 ["sqlite3__wasm_posix_create_file", "int", "string","*", "int"],
636 ["sqlite3__wasm_vfs_unlink", "int", "sqlite3_vfs*","string"],
637 ["sqlite3__wasm_qfmt_token","string:dealloc", "string","int"]
641 Install JS<->C struct bindings for the non-opaque struct types we
643 sqlite3.StructBinder = globalThis.Jaccwabyt({
644 heap: 0 ? wasm.memory : wasm.heap8u,
646 dealloc: wasm.dealloc,
647 bigIntEnabled: wasm.bigIntEnabled,
648 memberPrefix: /* Never change this: this prefix is baked into any
649 amount of code and client-facing docs. */ '$'
651 delete globalThis.Jaccwabyt;
653 {// wasm.xWrap() bindings...
655 /* Convert Arrays and certain TypedArrays to strings for
656 'string:flexible'-type arguments */
657 const __xString = wasm.xWrap.argAdapter('string');
658 wasm.xWrap.argAdapter(
659 'string:flexible', (v)=>__xString(util.flexibleString(v))
663 The 'string:static' argument adapter treats its argument as
666 - WASM pointer: assumed to be a long-lived C-string which gets
669 - Anything else: gets coerced to a JS string for use as a map
670 key. If a matching entry is found (as described next), it is
671 returned, else wasm.allocCString() is used to create a a new
672 string, map its pointer to (''+v) for the remainder of the
673 application's life, and returns that pointer value for this
674 call and all future calls which are passed a
675 string-equivalent argument.
677 Use case: sqlite3_bind_pointer() and sqlite3_result_pointer()
678 call for "a static string and preferably a string
679 literal." This converter is used to ensure that the string
680 value seen by those functions is long-lived and behaves as they
683 wasm.xWrap.argAdapter(
686 if(wasm.isPtr(v)) return v;
689 return rc || (this[v] = wasm.allocCString(v));
690 }.bind(Object.create(null))
694 Add some descriptive xWrap() aliases for '*' intended to (A)
695 initially improve readability/correctness of
696 wasm.bindingSignatures and (B) provide automatic conversion
697 from higher-level representations, e.g. capi.sqlite3_vfs to
698 `sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
700 const __xArgPtr = wasm.xWrap.argAdapter('*');
701 const nilType = function(){
702 /*a class which no value can ever be an instance of*/
704 wasm.xWrap.argAdapter('sqlite3_filename', __xArgPtr)
705 ('sqlite3_context*', __xArgPtr)
706 ('sqlite3_value*', __xArgPtr)
708 ('sqlite3_changegroup*', __xArgPtr)
709 ('sqlite3_changeset_iter*', __xArgPtr)
710 ('sqlite3_session*', __xArgPtr)
711 ('sqlite3_stmt*', (v)=>
712 __xArgPtr((v instanceof (sqlite3?.oo1?.Stmt || nilType))
715 __xArgPtr((v instanceof (sqlite3?.oo1?.DB || nilType))
717 ('sqlite3_index_info*', (v)=>
718 __xArgPtr((v instanceof (capi.sqlite3_index_info || nilType))
720 ('sqlite3_module*', (v)=>
721 __xArgPtr((v instanceof (capi.sqlite3_module || nilType))
726 - v is-a string: use the result of sqlite3_vfs_find(v) but
727 throw if it returns 0.
728 - v is-a capi.sqlite3_vfs: use v.pointer.
729 - Else return the same as the `'*'` argument conversion.
731 ('sqlite3_vfs*', (v)=>{
732 if('string'===typeof v){
733 /* A NULL sqlite3_vfs pointer will be treated as the default
734 VFS in many contexts. We specifically do not want that
736 return capi.sqlite3_vfs_find(v)
737 || sqlite3.SQLite3Error.toss(
738 capi.SQLITE_NOTFOUND,
739 "Unknown sqlite3_vfs name:", v
742 return __xArgPtr((v instanceof (capi.sqlite3_vfs || nilType))
746 const __xRcPtr = wasm.xWrap.resultAdapter('*');
747 wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr)
748 ('sqlite3_context*', __xRcPtr)
749 ('sqlite3_stmt*', __xRcPtr)
750 ('sqlite3_value*', __xRcPtr)
751 ('sqlite3_vfs*', __xRcPtr)
755 Populate api object with sqlite3_...() by binding the "raw" wasm
756 exports into type-converting proxies using wasm.xWrap().
758 if(0 === wasm.exports.sqlite3_step.length){
759 /* This environment wraps exports in nullary functions, which means
760 we must disable the arg-count validation we otherwise perform
762 wasm.xWrap.doArgcCheck = false;
764 "Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks."
767 for(const e of wasm.bindingSignatures){
768 capi[e[0]] = wasm.xWrap.apply(null, e);
770 for(const e of wasm.bindingSignatures.wasmInternal){
771 util[e[0]] = wasm.xWrap.apply(null, e);
774 /* For C API functions which cannot work properly unless
775 wasm.bigIntEnabled is true, install a bogus impl which throws
776 if called when bigIntEnabled is false. The alternative would be
777 to elide these functions altogether, which seems likely to
778 cause more confusion. */
779 const fI64Disabled = function(fname){
780 return ()=>toss(fname+"() is unavailable due to lack",
781 "of BigInt support in this build.");
783 for(const e of wasm.bindingSignatures.int64){
784 capi[e[0]] = wasm.bigIntEnabled
785 ? wasm.xWrap.apply(null, e)
786 : fI64Disabled(e[0]);
789 /* There's no need to expose bindingSignatures to clients,
790 implicitly making it part of the public interface. */
791 delete wasm.bindingSignatures;
793 if(wasm.exports.sqlite3__wasm_db_error){
794 const __db_err = wasm.xWrap(
795 'sqlite3__wasm_db_error', 'int', 'sqlite3*', 'int', 'string'
798 Sets the given db's error state. Accepts:
800 - (sqlite3*, int code, string msg)
801 - (sqlite3*, Error e [,string msg = ''+e])
803 If passed a WasmAllocError, the message is ignored and the
804 result code is SQLITE_NOMEM. If passed any other Error type,
805 the result code defaults to SQLITE_ERROR unless the Error
806 object has a resultCode property, in which case that is used
807 (e.g. SQLite3Error has that). If passed a non-WasmAllocError
808 exception, the message string defaults to theError.message.
810 Returns the resulting code. Pass (pDb,0,0) to clear the error
813 util.sqlite3__wasm_db_error = function(pDb, resultCode, message){
814 if(resultCode instanceof sqlite3.WasmAllocError){
815 resultCode = capi.SQLITE_NOMEM;
816 message = 0 /*avoid allocating message string*/;
817 }else if(resultCode instanceof Error){
818 message = message || ''+resultCode;
819 resultCode = (resultCode.resultCode || capi.SQLITE_ERROR);
821 return pDb ? __db_err(pDb, resultCode, message) : resultCode;
824 util.sqlite3__wasm_db_error = function(pDb,errCode,msg){
825 console.warn("sqlite3__wasm_db_error() is not exported.",arguments);
829 }/*xWrap() bindings*/
831 {/* Import C-level constants and structs... */
832 const cJson = wasm.xCall('sqlite3__wasm_enum_json');
834 toss("Maintenance required: increase sqlite3__wasm_enum_json()'s",
835 "static buffer size!");
837 //console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
838 wasm.ctype = JSON.parse(wasm.cstrToJs(cJson));
839 // Groups of SQLITE_xyz macros...
840 const defineGroups = ['access', 'authorizer',
841 'blobFinalizers', 'changeset',
842 'config', 'dataTypes',
843 'dbConfig', 'dbStatus',
844 'encodings', 'fcntl', 'flock', 'ioCap',
845 'limits', 'openFlags',
846 'prepareFlags', 'resultCodes',
848 'stmtStatus', 'syncFlags',
849 'trace', 'txnState', 'udfFlags',
851 if(wasm.bigIntEnabled){
852 defineGroups.push('serialize', 'session', 'vtab');
854 for(const t of defineGroups){
855 for(const e of Object.entries(wasm.ctype[t])){
856 // ^^^ [k,v] there triggers a buggy code transformation via
857 // one of the Emscripten-driven optimizers.
861 if(!wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)){
862 toss("Internal error: cannot resolve exported function",
863 "entry SQLITE_WASM_DEALLOC (=="+capi.SQLITE_WASM_DEALLOC+").");
865 const __rcMap = Object.create(null);
866 for(const t of ['resultCodes']){
867 for(const e of Object.entries(wasm.ctype[t])){
868 __rcMap[e[1]] = e[0];
872 For the given integer, returns the SQLITE_xxx result code as a
873 string, or undefined if no such mapping is found.
875 capi.sqlite3_js_rc_str = (rc)=>__rcMap[rc];
876 /* Bind all registered C-side structs... */
877 const notThese = Object.assign(Object.create(null),{
878 // For each struct to NOT register, map its name to true:
879 WasmTestStruct: true,
880 /* We unregister the kvvfs VFS from Worker threads below. */
881 sqlite3_kvvfs_methods: !util.isUIThread(),
882 /* sqlite3_index_info and friends require int64: */
883 sqlite3_index_info: !wasm.bigIntEnabled,
884 sqlite3_index_constraint: !wasm.bigIntEnabled,
885 sqlite3_index_orderby: !wasm.bigIntEnabled,
886 sqlite3_index_constraint_usage: !wasm.bigIntEnabled
888 for(const s of wasm.ctype.structs){
889 if(!notThese[s.name]){
890 capi[s.name] = sqlite3.StructBinder(s);
893 if(capi.sqlite3_index_info){
894 /* Move these inner structs into sqlite3_index_info. Binding
895 ** them to WASM requires that we create global-scope structs to
896 ** model them with, but those are no longer needed after we've
897 ** passed them to StructBinder. */
898 for(const k of ['sqlite3_index_constraint',
899 'sqlite3_index_orderby',
900 'sqlite3_index_constraint_usage']){
901 capi.sqlite3_index_info[k] = capi[k];
904 capi.sqlite3_vtab_config = wasm.xWrap(
905 'sqlite3__wasm_vtab_config','int',[
906 'sqlite3*', 'int', 'int']
908 }/* end vtab-related setup */
909 }/*end C constant and struct imports*/
912 Internal helper to assist in validating call argument counts in
913 the hand-written sqlite3_xyz() wrappers. We do this only for
914 consistency with non-special-case wrappings.
916 const __dbArgcMismatch = (pDb,f,n)=>{
917 return util.sqlite3__wasm_db_error(pDb, capi.SQLITE_MISUSE,
918 f+"() requires "+n+" argument"+
922 /** Code duplication reducer for functions which take an encoding
923 argument and require SQLITE_UTF8. Sets the db error code to
924 SQLITE_FORMAT and returns that code. */
925 const __errEncoding = (pDb)=>{
926 return util.sqlite3__wasm_db_error(
927 pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding."
932 __dbCleanupMap is infrastructure for recording registration of
933 UDFs and collations so that sqlite3_close_v2() can clean up any
934 automated JS-to-WASM function conversions installed by those.
936 const __argPDb = (pDb)=>wasm.xWrap.argAdapter('sqlite3*')(pDb);
937 const __argStr = (str)=>wasm.isPtr(str) ? wasm.cstrToJs(str) : str;
938 const __dbCleanupMap = function(
939 pDb, mode/*0=remove, >0=create if needed, <0=do not create if missing*/
942 let m = this.dbMap.get(pDb);
944 this.dbMap.delete(pDb);
946 }else if(!m && mode>0){
947 this.dbMap.set(pDb, (m = Object.create(null)));
950 }.bind(Object.assign(Object.create(null),{
954 __dbCleanupMap.addCollation = function(pDb, name){
955 const m = __dbCleanupMap(pDb, 1);
956 if(!m.collation) m.collation = new Set;
957 m.collation.add(__argStr(name).toLowerCase());
960 __dbCleanupMap._addUDF = function(pDb, name, arity, map){
961 /* Map UDF name to a Set of arity values */
962 name = __argStr(name).toLowerCase();
963 let u = map.get(name);
964 if(!u) map.set(name, (u = new Set));
965 u.add((arity<0) ? -1 : arity);
968 __dbCleanupMap.addFunction = function(pDb, name, arity){
969 const m = __dbCleanupMap(pDb, 1);
970 if(!m.udf) m.udf = new Map;
971 this._addUDF(pDb, name, arity, m.udf);
974 __dbCleanupMap.addWindowFunc = function(pDb, name, arity){
975 const m = __dbCleanupMap(pDb, 1);
976 if(!m.wudf) m.wudf = new Map;
977 this._addUDF(pDb, name, arity, m.wudf);
981 Intended to be called _only_ from sqlite3_close_v2(),
982 passed its non-0 db argument.
984 This function frees up certain automatically-installed WASM
985 function bindings which were installed on behalf of the given db,
986 as those may otherwise leak.
988 Notable caveat: this is only ever run via
989 sqlite3.capi.sqlite3_close_v2(). If a client, for whatever
990 reason, uses sqlite3.wasm.exports.sqlite3_close_v2() (the
991 function directly exported from WASM), this cleanup will not
994 This is not a silver bullet for avoiding automation-related
995 leaks but represents "an honest effort."
997 The issue being addressed here is covered at:
999 https://sqlite.org/wasm/doc/trunk/api-c-style.md#convert-func-ptr
1001 __dbCleanupMap.cleanup = function(pDb){
1002 pDb = __argPDb(pDb);
1003 //wasm.xWrap.FuncPtrAdapter.debugFuncInstall = false;
1005 Installing NULL functions in the C API will remove those
1006 bindings. The FuncPtrAdapter which sits between us and the C
1007 API will also treat that as an opportunity to
1008 wasm.uninstallFunction() any WASM function bindings it has
1011 const closeArgs = [pDb];
1013 'sqlite3_busy_handler',
1014 'sqlite3_commit_hook',
1015 'sqlite3_preupdate_hook',
1016 'sqlite3_progress_handler',
1017 'sqlite3_rollback_hook',
1018 'sqlite3_set_authorizer',
1020 'sqlite3_update_hook'
1022 const x = wasm.exports[name];
1023 closeArgs.length = x.length/*==argument count*/
1024 /* recall that undefined entries translate to 0 when passed to
1026 try{ capi[name](...closeArgs) }
1028 console.warn("close-time call of",name+"(",closeArgs,") threw:",e);
1031 const m = __dbCleanupMap(pDb, 0);
1034 for(const name of m.collation){
1036 capi.sqlite3_create_collation_v2(
1037 pDb, name, capi.SQLITE_UTF8, 0, 0, 0
1046 for(i = 0; i < 2; ++i){ /* Clean up UDFs... */
1047 const fmap = i ? m.wudf : m.udf;
1050 ? capi.sqlite3_create_window_function
1051 : capi.sqlite3_create_function_v2;
1052 for(const e of fmap){
1053 const name = e[0], arities = e[1];
1054 const fargs = [pDb, name, 0/*arity*/, capi.SQLITE_UTF8, 0, 0, 0, 0, 0];
1055 if(i) fargs.push(0);
1056 for(const arity of arities){
1057 try{ fargs[2] = arity; func.apply(null, fargs); }
1058 catch(e){/*ignored*/}
1066 }/*__dbCleanupMap.cleanup()*/;
1068 {/* Binding of sqlite3_close_v2() */
1069 const __sqlite3CloseV2 = wasm.xWrap("sqlite3_close_v2", "int", "sqlite3*");
1070 capi.sqlite3_close_v2 = function(pDb){
1071 if(1!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_close_v2', 1);
1073 try{__dbCleanupMap.cleanup(pDb)} catch(e){/*ignored*/}
1075 return __sqlite3CloseV2(pDb);
1077 }/*sqlite3_close_v2()*/
1079 if(capi.sqlite3session_table_filter){
1080 const __sqlite3SessionDelete = wasm.xWrap(
1081 'sqlite3session_delete', undefined, ['sqlite3_session*']
1083 capi.sqlite3session_delete = function(pSession){
1084 if(1!==arguments.length){
1085 return __dbArgcMismatch(pDb, 'sqlite3session_delete', 1);
1086 /* Yes, we're returning a value from a void function. That seems
1087 like the lesser evil compared to not maintaining arg-count
1088 consistency as we do with other similar bindings. */
1091 //wasm.xWrap.FuncPtrAdapter.debugFuncInstall = true;
1092 capi.sqlite3session_table_filter(pSession, 0, 0);
1094 __sqlite3SessionDelete(pSession);
1098 {/* Bindings for sqlite3_create_collation[_v2]() */
1099 // contextKey() impl for wasm.xWrap.FuncPtrAdapter
1100 const contextKey = (argv,argIndex)=>{
1101 return 'argv['+argIndex+']:'+argv[0/* sqlite3* */]+
1102 ':'+wasm.cstrToJs(argv[1/* collation name */]).toLowerCase()
1104 const __sqlite3CreateCollationV2 = wasm.xWrap(
1105 'sqlite3_create_collation_v2', 'int', [
1106 'sqlite3*', 'string', 'int', '*',
1107 new wasm.xWrap.FuncPtrAdapter({
1108 /* int(*xCompare)(void*,int,const void*,int,const void*) */
1109 name: 'xCompare', signature: 'i(pipip)', contextKey
1111 new wasm.xWrap.FuncPtrAdapter({
1112 /* void(*xDestroy(void*) */
1113 name: 'xDestroy', signature: 'v(p)', contextKey
1119 Works exactly like C's sqlite3_create_collation_v2() except that:
1121 1) It returns capi.SQLITE_FORMAT if the 3rd argument contains
1122 any encoding-related value other than capi.SQLITE_UTF8. No
1123 other encodings are supported. As a special case, if the
1124 bottom 4 bits of that argument are 0, SQLITE_UTF8 is
1127 2) It accepts JS functions for its function-pointer arguments,
1128 for which it will install WASM-bound proxies. The bindings
1129 are "permanent," in that they will stay in the WASM environment
1130 until it shuts down unless the client calls this again with the
1131 same collation name and a value of 0 or null for the
1132 the function pointer(s).
1134 For consistency with the C API, it requires the same number of
1135 arguments. It returns capi.SQLITE_MISUSE if passed any other
1138 Returns 0 on success, non-0 on error, in which case the error
1139 state of pDb (of type `sqlite3*` or argument-convertible to it)
1140 may contain more information.
1142 capi.sqlite3_create_collation_v2 = function(pDb,zName,eTextRep,pArg,xCompare,xDestroy){
1143 if(6!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_create_collation_v2', 6);
1144 else if( 0 === (eTextRep & 0xf) ){
1145 eTextRep |= capi.SQLITE_UTF8;
1146 }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
1147 return __errEncoding(pDb);
1150 const rc = __sqlite3CreateCollationV2(pDb, zName, eTextRep, pArg, xCompare, xDestroy);
1151 if(0===rc && xCompare instanceof Function){
1152 __dbCleanupMap.addCollation(pDb, zName);
1156 return util.sqlite3__wasm_db_error(pDb, e);
1160 capi.sqlite3_create_collation = (pDb,zName,eTextRep,pArg,xCompare)=>{
1161 return (5===arguments.length)
1162 ? capi.sqlite3_create_collation_v2(pDb,zName,eTextRep,pArg,xCompare,0)
1163 : __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5);
1166 }/*sqlite3_create_collation() and friends*/
1168 {/* Special-case handling of sqlite3_create_function_v2()
1169 and sqlite3_create_window_function(). */
1170 /** FuncPtrAdapter for contextKey() for sqlite3_create_function()
1172 const contextKey = function(argv,argIndex){
1174 argv[0/* sqlite3* */]
1175 +':'+(argv[2/*number of UDF args*/] < 0 ? -1 : argv[2])
1176 +':'+argIndex/*distinct for each xAbc callback type*/
1177 +':'+wasm.cstrToJs(argv[1]).toLowerCase()
1182 JS proxies for the various sqlite3_create[_window]_function()
1183 callbacks, structured in a form usable by wasm.xWrap.FuncPtrAdapter.
1185 const __cfProxy = Object.assign(Object.create(null), {
1187 signature:'v(pip)', contextKey,
1188 callProxy: (callback)=>{
1189 return (pCtx, argc, pArgv)=>{
1190 try{ callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) }
1191 catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
1196 signature:'v(p)', contextKey,
1197 callProxy: (callback)=>{
1199 try{ capi.sqlite3_result_js(pCtx, callback(pCtx)) }
1200 catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
1205 signature:'v(pip)', contextKey,
1206 callProxy: (callback)=>{
1207 return (pCtx, argc, pArgv)=>{
1209 capi.sqlite3_result_js(
1211 callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv))
1214 //console.error('xFunc() caught:',e);
1215 capi.sqlite3_result_error_js(pCtx, e);
1221 signature:'v(p)', contextKey,
1222 //Arguable: a well-behaved destructor doesn't require a proxy.
1223 callProxy: (callback)=>{
1225 try{ callback(pVoid) }
1226 catch(e){ console.error("UDF xDestroy method threw:",e) }
1232 const __sqlite3CreateFunction = wasm.xWrap(
1233 "sqlite3_create_function_v2", "int", [
1234 "sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
1235 "int"/*eTextRep*/, "*"/*pApp*/,
1236 new wasm.xWrap.FuncPtrAdapter({name: 'xFunc', ...__cfProxy.xFunc}),
1237 new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}),
1238 new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}),
1239 new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy})
1243 const __sqlite3CreateWindowFunction = wasm.xWrap(
1244 "sqlite3_create_window_function", "int", [
1245 "sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
1246 "int"/*eTextRep*/, "*"/*pApp*/,
1247 new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}),
1248 new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}),
1249 new wasm.xWrap.FuncPtrAdapter({name: 'xValue', ...__cfProxy.xFinalAndValue}),
1250 new wasm.xWrap.FuncPtrAdapter({name: 'xInverse', ...__cfProxy.xInverseAndStep}),
1251 new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy})
1255 /* Documented in the api object's initializer. */
1256 capi.sqlite3_create_function_v2 = function f(
1257 pDb, funcName, nArg, eTextRep, pApp,
1258 xFunc, //void (*xFunc)(sqlite3_context*,int,sqlite3_value**)
1259 xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
1260 xFinal, //void (*xFinal)(sqlite3_context*)
1261 xDestroy //void (*xDestroy)(void*)
1263 if( f.length!==arguments.length ){
1264 return __dbArgcMismatch(pDb,"sqlite3_create_function_v2",f.length);
1265 }else if( 0 === (eTextRep & 0xf) ){
1266 eTextRep |= capi.SQLITE_UTF8;
1267 }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
1268 return __errEncoding(pDb);
1271 const rc = __sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
1272 pApp, xFunc, xStep, xFinal, xDestroy);
1273 if(0===rc && (xFunc instanceof Function
1274 || xStep instanceof Function
1275 || xFinal instanceof Function
1276 || xDestroy instanceof Function)){
1277 __dbCleanupMap.addFunction(pDb, funcName, nArg);
1281 console.error("sqlite3_create_function_v2() setup threw:",e);
1282 return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
1286 /* Documented in the api object's initializer. */
1287 capi.sqlite3_create_function = function f(
1288 pDb, funcName, nArg, eTextRep, pApp,
1289 xFunc, xStep, xFinal
1291 return (f.length===arguments.length)
1292 ? capi.sqlite3_create_function_v2(pDb, funcName, nArg, eTextRep,
1293 pApp, xFunc, xStep, xFinal, 0)
1294 : __dbArgcMismatch(pDb,"sqlite3_create_function",f.length);
1297 /* Documented in the api object's initializer. */
1298 capi.sqlite3_create_window_function = function f(
1299 pDb, funcName, nArg, eTextRep, pApp,
1300 xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
1301 xFinal, //void (*xFinal)(sqlite3_context*)
1302 xValue, //void (*xValue)(sqlite3_context*)
1303 xInverse,//void (*xInverse)(sqlite3_context*,int,sqlite3_value**)
1304 xDestroy //void (*xDestroy)(void*)
1306 if( f.length!==arguments.length ){
1307 return __dbArgcMismatch(pDb,"sqlite3_create_window_function",f.length);
1308 }else if( 0 === (eTextRep & 0xf) ){
1309 eTextRep |= capi.SQLITE_UTF8;
1310 }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
1311 return __errEncoding(pDb);
1314 const rc = __sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep,
1315 pApp, xStep, xFinal, xValue,
1316 xInverse, xDestroy);
1317 if(0===rc && (xStep instanceof Function
1318 || xFinal instanceof Function
1319 || xValue instanceof Function
1320 || xInverse instanceof Function
1321 || xDestroy instanceof Function)){
1322 __dbCleanupMap.addWindowFunc(pDb, funcName, nArg);
1326 console.error("sqlite3_create_window_function() setup threw:",e);
1327 return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
1331 A _deprecated_ alias for capi.sqlite3_result_js() which
1332 predates the addition of that function in the public API.
1334 capi.sqlite3_create_function_v2.udfSetResult =
1335 capi.sqlite3_create_function.udfSetResult =
1336 capi.sqlite3_create_window_function.udfSetResult = capi.sqlite3_result_js;
1339 A _deprecated_ alias for capi.sqlite3_values_to_js() which
1340 predates the addition of that function in the public API.
1342 capi.sqlite3_create_function_v2.udfConvertArgs =
1343 capi.sqlite3_create_function.udfConvertArgs =
1344 capi.sqlite3_create_window_function.udfConvertArgs = capi.sqlite3_values_to_js;
1347 A _deprecated_ alias for capi.sqlite3_result_error_js() which
1348 predates the addition of that function in the public API.
1350 capi.sqlite3_create_function_v2.udfSetError =
1351 capi.sqlite3_create_function.udfSetError =
1352 capi.sqlite3_create_window_function.udfSetError = capi.sqlite3_result_error_js;
1354 }/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/;
1356 {/* Special-case handling of sqlite3_prepare_v2() and
1357 sqlite3_prepare_v3() */
1360 Helper for string:flexible conversions which require a
1361 byte-length counterpart argument. Passed a value and its
1362 ostensible length, this function returns [V,N], where V is
1363 either v or a transformed copy of v and N is either n, -1, or
1364 the byte length of v (if it's a byte array or ArrayBuffer).
1366 const __flexiString = (v,n)=>{
1367 if('string'===typeof v){
1369 }else if(util.isSQLableTypedArray(v)){
1371 v = util.typedArrayToString(
1372 (v instanceof ArrayBuffer) ? new Uint8Array(v) : v
1374 }else if(Array.isArray(v)){
1382 Scope-local holder of the two impls of sqlite3_prepare_v2/v3().
1386 This binding expects a JS string as its 2nd argument and
1387 null as its final argument. In order to compile multiple
1388 statements from a single string, the "full" impl (see
1389 below) must be used.
1391 basic: wasm.xWrap('sqlite3_prepare_v3',
1392 "int", ["sqlite3*", "string",
1393 "int"/*ignored for this impl!*/,
1395 "**"/*MUST be 0 or null or undefined!*/]),
1397 Impl which requires that the 2nd argument be a pointer
1398 to the SQL string, instead of being converted to a
1399 string. This variant is necessary for cases where we
1400 require a non-NULL value for the final argument
1401 (exec()'ing multiple statements from one input
1402 string). For simpler cases, where only the first
1403 statement in the SQL string is required, the wrapper
1404 named sqlite3_prepare_v2() is sufficient and easier to
1405 use because it doesn't require dealing with pointers.
1407 full: wasm.xWrap('sqlite3_prepare_v3',
1408 "int", ["sqlite3*", "*", "int", "int",
1412 /* Documented in the capi object's initializer. */
1413 capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){
1414 if(f.length!==arguments.length){
1415 return __dbArgcMismatch(pDb,"sqlite3_prepare_v3",f.length);
1417 const [xSql, xSqlLen] = __flexiString(sql, sqlLen);
1418 switch(typeof xSql){
1419 case 'string': return __prepare.basic(pDb, xSql, xSqlLen, prepFlags, ppStmt, null);
1420 case 'number': return __prepare.full(pDb, xSql, xSqlLen, prepFlags, ppStmt, pzTail);
1422 return util.sqlite3__wasm_db_error(
1423 pDb, capi.SQLITE_MISUSE,
1424 "Invalid SQL argument type for sqlite3_prepare_v2/v3()."
1429 /* Documented in the capi object's initializer. */
1430 capi.sqlite3_prepare_v2 = function f(pDb, sql, sqlLen, ppStmt, pzTail){
1431 return (f.length===arguments.length)
1432 ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail)
1433 : __dbArgcMismatch(pDb,"sqlite3_prepare_v2",f.length);
1436 }/*sqlite3_prepare_v2/v3()*/
1438 {/*sqlite3_bind_text/blob()*/
1439 const __bindText = wasm.xWrap("sqlite3_bind_text", "int", [
1440 "sqlite3_stmt*", "int", "string", "int", "*"
1442 const __bindBlob = wasm.xWrap("sqlite3_bind_blob", "int", [
1443 "sqlite3_stmt*", "int", "*", "int", "*"
1446 /** Documented in the capi object's initializer. */
1447 capi.sqlite3_bind_text = function f(pStmt, iCol, text, nText, xDestroy){
1448 if(f.length!==arguments.length){
1449 return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt),
1450 "sqlite3_bind_text", f.length);
1451 }else if(wasm.isPtr(text) || null===text){
1452 return __bindText(pStmt, iCol, text, nText, xDestroy);
1453 }else if(text instanceof ArrayBuffer){
1454 text = new Uint8Array(text);
1455 }else if(Array.isArray(pMem)){
1456 text = pMem.join('');
1460 if(util.isSQLableTypedArray(text)){
1461 p = wasm.allocFromTypedArray(text);
1462 n = text.byteLength;
1463 }else if('string'===typeof text){
1464 [p, n] = wasm.allocCString(text);
1466 return util.sqlite3__wasm_db_error(
1467 capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
1468 "Invalid 3rd argument type for sqlite3_bind_text()."
1471 return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
1474 return util.sqlite3__wasm_db_error(
1475 capi.sqlite3_db_handle(pStmt), e
1478 }/*sqlite3_bind_text()*/;
1480 /** Documented in the capi object's initializer. */
1481 capi.sqlite3_bind_blob = function f(pStmt, iCol, pMem, nMem, xDestroy){
1482 if(f.length!==arguments.length){
1483 return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt),
1484 "sqlite3_bind_blob", f.length);
1485 }else if(wasm.isPtr(pMem) || null===pMem){
1486 return __bindBlob(pStmt, iCol, pMem, nMem, xDestroy);
1487 }else if(pMem instanceof ArrayBuffer){
1488 pMem = new Uint8Array(pMem);
1489 }else if(Array.isArray(pMem)){
1490 pMem = pMem.join('');
1494 if(util.isBindableTypedArray(pMem)){
1495 p = wasm.allocFromTypedArray(pMem);
1496 n = nMem>=0 ? nMem : pMem.byteLength;
1497 }else if('string'===typeof pMem){
1498 [p, n] = wasm.allocCString(pMem);
1500 return util.sqlite3__wasm_db_error(
1501 capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
1502 "Invalid 3rd argument type for sqlite3_bind_blob()."
1505 return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
1508 return util.sqlite3__wasm_db_error(
1509 capi.sqlite3_db_handle(pStmt), e
1512 }/*sqlite3_bind_blob()*/;
1514 }/*sqlite3_bind_text/blob()*/
1516 {/* sqlite3_config() */
1518 Wraps a small subset of the C API's sqlite3_config() options.
1519 Unsupported options trigger the return of capi.SQLITE_NOTFOUND.
1520 Passing fewer than 2 arguments triggers return of
1523 capi.sqlite3_config = function(op, ...args){
1524 if(arguments.length<2) return capi.SQLITE_MISUSE;
1526 case capi.SQLITE_CONFIG_COVERING_INDEX_SCAN: // 20 /* int */
1527 case capi.SQLITE_CONFIG_MEMSTATUS:// 9 /* boolean */
1528 case capi.SQLITE_CONFIG_SMALL_MALLOC: // 27 /* boolean */
1529 case capi.SQLITE_CONFIG_SORTERREF_SIZE: // 28 /* int nByte */
1530 case capi.SQLITE_CONFIG_STMTJRNL_SPILL: // 26 /* int nByte */
1531 case capi.SQLITE_CONFIG_URI:// 17 /* int */
1532 return wasm.exports.sqlite3__wasm_config_i(op, args[0]);
1533 case capi.SQLITE_CONFIG_LOOKASIDE: // 13 /* int int */
1534 return wasm.exports.sqlite3__wasm_config_ii(op, args[0], args[1]);
1535 case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: // 29 /* sqlite3_int64 */
1536 return wasm.exports.sqlite3__wasm_config_j(op, args[0]);
1537 case capi.SQLITE_CONFIG_GETMALLOC: // 5 /* sqlite3_mem_methods* */
1538 case capi.SQLITE_CONFIG_GETMUTEX: // 11 /* sqlite3_mutex_methods* */
1539 case capi.SQLITE_CONFIG_GETPCACHE2: // 19 /* sqlite3_pcache_methods2* */
1540 case capi.SQLITE_CONFIG_GETPCACHE: // 15 /* no-op */
1541 case capi.SQLITE_CONFIG_HEAP: // 8 /* void*, int nByte, int min */
1542 case capi.SQLITE_CONFIG_LOG: // 16 /* xFunc, void* */
1543 case capi.SQLITE_CONFIG_MALLOC:// 4 /* sqlite3_mem_methods* */
1544 case capi.SQLITE_CONFIG_MMAP_SIZE: // 22 /* sqlite3_int64, sqlite3_int64 */
1545 case capi.SQLITE_CONFIG_MULTITHREAD: // 2 /* nil */
1546 case capi.SQLITE_CONFIG_MUTEX: // 10 /* sqlite3_mutex_methods* */
1547 case capi.SQLITE_CONFIG_PAGECACHE: // 7 /* void*, int sz, int N */
1548 case capi.SQLITE_CONFIG_PCACHE2: // 18 /* sqlite3_pcache_methods2* */
1549 case capi.SQLITE_CONFIG_PCACHE: // 14 /* no-op */
1550 case capi.SQLITE_CONFIG_PCACHE_HDRSZ: // 24 /* int *psz */
1551 case capi.SQLITE_CONFIG_PMASZ: // 25 /* unsigned int szPma */
1552 case capi.SQLITE_CONFIG_SERIALIZED: // 3 /* nil */
1553 case capi.SQLITE_CONFIG_SINGLETHREAD: // 1 /* nil */:
1554 case capi.SQLITE_CONFIG_SQLLOG: // 21 /* xSqllog, void* */
1555 case capi.SQLITE_CONFIG_WIN32_HEAPSIZE: // 23 /* int nByte */
1557 /* maintenance note: we specifically do not include
1558 SQLITE_CONFIG_ROWID_IN_VIEW here, on the grounds that
1559 it's only for legacy support and no apps written with
1560 this API require that. */
1561 return capi.SQLITE_NOTFOUND;
1564 }/* sqlite3_config() */
1566 {/*auto-extension bindings.*/
1567 const __autoExtFptr = new Set;
1569 capi.sqlite3_auto_extension = function(fPtr){
1570 if( fPtr instanceof Function ){
1571 fPtr = wasm.installFunction('i(ppp)', fPtr);
1572 }else if( 1!==arguments.length || !wasm.isPtr(fPtr) ){
1573 return capi.SQLITE_MISUSE;
1575 const rc = wasm.exports.sqlite3_auto_extension(fPtr);
1576 if( fPtr!==arguments[0] ){
1577 if(0===rc) __autoExtFptr.add(fPtr);
1578 else wasm.uninstallFunction(fPtr);
1583 capi.sqlite3_cancel_auto_extension = function(fPtr){
1584 /* We do not do an automatic JS-to-WASM function conversion here
1585 because it would be senseless: the converted pointer would
1586 never possibly match an already-installed one. */;
1587 if(!fPtr || 1!==arguments.length || !wasm.isPtr(fPtr)) return 0;
1588 return wasm.exports.sqlite3_cancel_auto_extension(fPtr);
1589 /* Note that it "cannot happen" that a client passes a pointer which
1590 is in __autoExtFptr because __autoExtFptr only contains automatic
1591 conversions created inside sqlite3_auto_extension() and
1592 never exposed to the client. */
1595 capi.sqlite3_reset_auto_extension = function(){
1596 wasm.exports.sqlite3_reset_auto_extension();
1597 for(const fp of __autoExtFptr) wasm.uninstallFunction(fp);
1598 __autoExtFptr.clear();
1600 }/* auto-extension */
1602 const pKvvfs = capi.sqlite3_vfs_find("kvvfs");
1603 if( pKvvfs ){/* kvvfs-specific glue */
1604 if(util.isUIThread()){
1605 const kvvfsMethods = new capi.sqlite3_kvvfs_methods(
1606 wasm.exports.sqlite3__wasm_kvvfs_methods()
1608 delete capi.sqlite3_kvvfs_methods;
1610 const kvvfsMakeKey = wasm.exports.sqlite3__wasm_kvvfsMakeKeyOnPstack,
1611 pstack = wasm.pstack;
1613 const kvvfsStorage = (zClass)=>
1614 ((115/*=='s'*/===wasm.peek(zClass))
1615 ? sessionStorage : localStorage);
1618 Implementations for members of the object referred to by
1619 sqlite3__wasm_kvvfs_methods(). We swap out the native
1620 implementations with these, which use localStorage or
1621 sessionStorage for their backing store.
1623 const kvvfsImpls = {
1624 xRead: (zClass, zKey, zBuf, nBuf)=>{
1625 const stack = pstack.pointer,
1626 astack = wasm.scopedAllocPush();
1628 const zXKey = kvvfsMakeKey(zClass,zKey);
1629 if(!zXKey) return -3/*OOM*/;
1630 const jKey = wasm.cstrToJs(zXKey);
1631 const jV = kvvfsStorage(zClass).getItem(jKey);
1633 const nV = jV.length /* Note that we are relying 100% on v being
1634 ASCII so that jV.length is equal to the
1635 C-string's byte length. */;
1636 if(nBuf<=0) return nV;
1641 const zV = wasm.scopedAllocCString(jV);
1642 if(nBuf > nV + 1) nBuf = nV + 1;
1643 wasm.heap8u().copyWithin(zBuf, zV, zV + nBuf - 1);
1644 wasm.poke(zBuf + nBuf - 1, 0);
1647 console.error("kvstorageRead()",e);
1650 pstack.restore(stack);
1651 wasm.scopedAllocPop(astack);
1654 xWrite: (zClass, zKey, zData)=>{
1655 const stack = pstack.pointer;
1657 const zXKey = kvvfsMakeKey(zClass,zKey);
1658 if(!zXKey) return 1/*OOM*/;
1659 const jKey = wasm.cstrToJs(zXKey);
1660 kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData));
1663 console.error("kvstorageWrite()",e);
1664 return capi.SQLITE_IOERR;
1666 pstack.restore(stack);
1669 xDelete: (zClass, zKey)=>{
1670 const stack = pstack.pointer;
1672 const zXKey = kvvfsMakeKey(zClass,zKey);
1673 if(!zXKey) return 1/*OOM*/;
1674 kvvfsStorage(zClass).removeItem(wasm.cstrToJs(zXKey));
1677 console.error("kvstorageDelete()",e);
1678 return capi.SQLITE_IOERR;
1680 pstack.restore(stack);
1684 for(const k of Object.keys(kvvfsImpls)){
1685 kvvfsMethods[kvvfsMethods.memberKey(k)] =
1686 wasm.installFunction(
1687 kvvfsMethods.memberSignature(k),
1692 /* Worker thread: unregister kvvfs to avoid it being used
1693 for anything other than local/sessionStorage. It "can"
1694 be used that way but it's not really intended to be. */
1695 capi.sqlite3_vfs_unregister(pKvvfs);
1699 /* Warn if client-level code makes use of FuncPtrAdapter. */
1700 wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
1702 const StructBinder = sqlite3.StructBinder
1703 /* we require a local alias b/c StructBinder is removed from the sqlite3
1704 object during the final steps of the API cleanup. */;
1706 Installs a StructBinder-bound function pointer member of the
1707 given name and function in the given StructBinder.StructType
1710 It creates a WASM proxy for the given function and arranges for
1711 that proxy to be cleaned up when tgt.dispose() is called. Throws
1712 on the slightest hint of error, e.g. tgt is-not-a StructType,
1713 name does not map to a struct-bound member, etc.
1715 As a special case, if the given function is a pointer, then
1716 `wasm.functionEntry()` is used to validate that it is a known
1717 function. If so, it is used as-is with no extra level of proxying
1718 or cleanup, else an exception is thrown. It is legal to pass a
1719 value of 0, indicating a NULL pointer, with the caveat that 0
1720 _is_ a legal function pointer in WASM but it will not be accepted
1721 as such _here_. (Justification: the function at address zero must
1722 be one which initially came from the WASM module, not a method we
1723 want to bind to a virtual table or VFS.)
1725 This function returns a proxy for itself which is bound to tgt
1726 and takes 2 args (name,func). That function returns the same
1727 thing as this one, permitting calls to be chained.
1729 If called with only 1 arg, it has no side effects but returns a
1730 func with the same signature as described above.
1732 ACHTUNG: because we cannot generically know how to transform JS
1733 exceptions into result codes, the installed functions do no
1734 automatic catching of exceptions. It is critical, to avoid
1735 undefined behavior in the C layer, that methods mapped via
1736 this function do not throw. The exception, as it were, to that
1739 If applyArgcCheck is true then each JS function (as opposed to
1740 function pointers) gets wrapped in a proxy which asserts that it
1741 is passed the expected number of arguments, throwing if the
1742 argument count does not match expectations. That is only intended
1743 for dev-time usage for sanity checking, and may leave the C
1744 environment in an undefined state.
1746 const installMethod = function callee(
1747 tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
1749 if(!(tgt instanceof StructBinder.StructType)){
1750 toss("Usage error: target object is-not-a StructType.");
1751 }else if(!(func instanceof Function) && !wasm.isPtr(func)){
1752 toss("Usage errror: expecting a Function or WASM pointer to one.");
1754 if(1===arguments.length){
1755 return (n,f)=>callee(tgt, n, f, applyArgcCheck);
1757 if(!callee.argcProxy){
1758 callee.argcProxy = function(tgt, funcName, func,sig){
1759 return function(...args){
1760 if(func.length!==arguments.length){
1761 toss("Argument mismatch for",
1762 tgt.structInfo.name+"::"+funcName
1763 +": Native signature is:",sig);
1765 return func.apply(this, args);
1768 /* An ondispose() callback for use with
1769 StructBinder-created types. */
1770 callee.removeFuncList = function(){
1771 if(this.ondispose.__removeFuncList){
1772 this.ondispose.__removeFuncList.forEach(
1774 if('number'===typeof v){
1775 try{wasm.uninstallFunction(v)}
1776 catch(e){/*ignore*/}
1778 /* else it's a descriptive label for the next number in
1782 delete this.ondispose.__removeFuncList;
1786 const sigN = tgt.memberSignature(name);
1788 toss("Member",name,"does not have a function pointer signature:",sigN);
1790 const memKey = tgt.memberKey(name);
1791 const fProxy = (applyArgcCheck && !wasm.isPtr(func))
1792 /** This middle-man proxy is only for use during development, to
1793 confirm that we always pass the proper number of
1794 arguments. We know that the C-level code will always use the
1795 correct argument count. */
1796 ? callee.argcProxy(tgt, memKey, func, sigN)
1798 if(wasm.isPtr(fProxy)){
1799 if(fProxy && !wasm.functionEntry(fProxy)){
1800 toss("Pointer",fProxy,"is not a WASM function table entry.");
1802 tgt[memKey] = fProxy;
1804 const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
1805 tgt[memKey] = pFunc;
1806 if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
1807 tgt.addOnDispose('ondispose.__removeFuncList handler',
1808 callee.removeFuncList);
1809 tgt.ondispose.__removeFuncList = [];
1811 tgt.ondispose.__removeFuncList.push(memKey, pFunc);
1813 return (n,f)=>callee(tgt, n, f, applyArgcCheck);
1815 installMethod.installMethodArgcCheck = false;
1818 Installs methods into the given StructBinder.StructType-type
1819 instance. Each entry in the given methods object must map to a
1820 known member of the given StructType, else an exception will be
1821 triggered. See installMethod() for more details, including the
1822 semantics of the 3rd argument.
1824 As an exception to the above, if any two or more methods in the
1825 2nd argument are the exact same function, installMethod() is
1826 _not_ called for the 2nd and subsequent instances, and instead
1827 those instances get assigned the same method pointer which is
1828 created for the first instance. This optimization is primarily to
1829 accommodate special handling of sqlite3_module::xConnect and
1832 On success, returns its first argument. Throws on error.
1834 const installMethods = function(
1835 structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck
1837 const seen = new Map /* map of <Function, memberName> */;
1838 for(const k of Object.keys(methods)){
1839 const m = methods[k];
1840 const prior = seen.get(m);
1842 const mkey = structInstance.memberKey(k);
1843 structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
1845 installMethod(structInstance, k, m, applyArgcCheck);
1849 return structInstance;
1853 Equivalent to calling installMethod(this,...arguments) with a
1854 first argument of this object. If called with 1 or 2 arguments
1855 and the first is an object, it's instead equivalent to calling
1856 installMethods(this,...arguments).
1858 StructBinder.StructType.prototype.installMethod = function callee(
1859 name, func, applyArgcCheck = installMethod.installMethodArgcCheck
1861 return (arguments.length < 3 && name && 'object'===typeof name)
1862 ? installMethods(this, ...arguments)
1863 : installMethod(this, ...arguments);
1867 Equivalent to calling installMethods() with a first argument
1870 StructBinder.StructType.prototype.installMethods = function(
1871 methods, applyArgcCheck = installMethod.installMethodArgcCheck
1873 return installMethods(this, methods, applyArgcCheck);