1/* 2 2022-05-22 3 4 The author disclaims copyright to this source code. In place of a 5 legal notice, here is a blessing: 6 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. 10 11 *********************************************************************** 12 13 This file is intended to be combined at build-time with other 14 related code, most notably a header and footer which wraps this whole 15 file into an Emscripten Module.postRun() handler which has a parameter 16 named "Module" (the Emscripten Module object). The exact requirements, 17 conventions, and build process are very much under construction and 18 will be (re)documented once they've stopped fluctuating so much. 19 20 Specific goals of this project: 21 22 - Except where noted in the non-goals, provide a more-or-less 23 feature-complete wrapper to the sqlite3 C API, insofar as WASM 24 feature parity with C allows for. In fact, provide at least 3 25 APIs... 26 27 1) Bind a low-level sqlite3 API which is as close to the native 28 one as feasible in terms of usage. 29 30 2) A higher-level API, more akin to sql.js and node.js-style 31 implementations. This one speaks directly to the low-level 32 API. This API must be used from the same thread as the 33 low-level API. 34 35 3) A second higher-level API which speaks to the previous APIs via 36 worker messages. This one is intended for use in the main 37 thread, with the lower-level APIs installed in a Worker thread, 38 and talking to them via Worker messages. Because Workers are 39 asynchronouns and have only a single message channel, some 40 acrobatics are needed here to feed async work results back to 41 the client (as we cannot simply pass around callbacks between 42 the main and Worker threads). 43 44 - Insofar as possible, support client-side storage using JS 45 filesystem APIs. As of this writing, such things are still very 46 much under development. 47 48 Specific non-goals of this project: 49 50 - As WASM is a web-centric technology and UTF-8 is the King of 51 Encodings in that realm, there are no currently plans to support 52 the UTF16-related sqlite3 APIs. They would add a complication to 53 the bindings for no appreciable benefit. Though web-related 54 implementation details take priority, and the JavaScript 55 components of the API specifically focus on browser clients, the 56 lower-level WASM module "should" work in non-web WASM 57 environments. 58 59 - Supporting old or niche-market platforms. WASM is built for a 60 modern web and requires modern platforms. 61 62 - Though scalar User-Defined Functions (UDFs) may be created in 63 JavaScript, there are currently no plans to add support for 64 aggregate and window functions. 65 66 Attribution: 67 68 This project is endebted to the work of sql.js: 69 70 https://github.com/sql-js/sql.js 71 72 sql.js was an essential stepping stone in this code's development as 73 it demonstrated how to handle some of the WASM-related voodoo (like 74 handling pointers-to-pointers and adding JS implementations of 75 C-bound callback functions). These APIs have a considerably 76 different shape than sql.js's, however. 77*/ 78 79/** 80 sqlite3ApiBootstrap() is the only global symbol persistently 81 exposed by this API. It is intended to be called one time at the 82 end of the API amalgamation process, passed configuration details 83 for the current environment, and then optionally be removed from 84 the global object using `delete self.sqlite3ApiBootstrap`. 85 86 This function expects a configuration object, intended to abstract 87 away details specific to any given WASM environment, primarily so 88 that it can be used without any _direct_ dependency on 89 Emscripten. (Note the default values for the config object!) The 90 config object is only honored the first time this is 91 called. Subsequent calls ignore the argument and return the same 92 (configured) object which gets initialized by the first call. 93 94 The config object properties include: 95 96 - `exports`[^1]: the "exports" object for the current WASM 97 environment. In an Emscripten build, this should be set to 98 `Module['asm']`. 99 100 - `memory`[^1]: optional WebAssembly.Memory object, defaulting to 101 `exports.memory`. In Emscripten environments this should be set 102 to `Module.wasmMemory` if the build uses `-sIMPORT_MEMORY`, or be 103 left undefined/falsy to default to `exports.memory` when using 104 WASM-exported memory. 105 106 - `bigIntEnabled`: true if BigInt support is enabled. Defaults to 107 true if self.BigInt64Array is available, else false. Some APIs 108 will throw exceptions if called without BigInt support, as BigInt 109 is required for marshalling C-side int64 into and out of JS. 110 111 - `allocExportName`: the name of the function, in `exports`, of the 112 `malloc(3)`-compatible routine for the WASM environment. Defaults 113 to `"malloc"`. 114 115 - `deallocExportName`: the name of the function, in `exports`, of 116 the `free(3)`-compatible routine for the WASM 117 environment. Defaults to `"free"`. 118 119 - `wasmfsOpfsDir`[^1]: if the environment supports persistent storage, this 120 directory names the "mount point" for that directory. It must be prefixed 121 by `/` and may currently contain only a single directory-name part. Using 122 the root directory name is not supported by any current persistent backend. 123 124 125 [^1] = This property may optionally be a function, in which case this 126 function re-assigns it to the value returned from that function, 127 enabling delayed evaluation. 128 129*/ 130'use strict'; 131self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap( 132 apiConfig = (self.sqlite3ApiConfig || sqlite3ApiBootstrap.defaultConfig) 133){ 134 if(sqlite3ApiBootstrap.sqlite3){ /* already initalized */ 135 console.warn("sqlite3ApiBootstrap() called multiple times.", 136 "Config and external initializers are ignored on calls after the first."); 137 return sqlite3ApiBootstrap.sqlite3; 138 } 139 const config = Object.assign(Object.create(null),{ 140 exports: undefined, 141 memory: undefined, 142 bigIntEnabled: (()=>{ 143 if('undefined'!==typeof Module){ 144 /* Emscripten module will contain HEAPU64 when built with 145 -sWASM_BIGINT=1, else it will not. */ 146 return !!Module.HEAPU64; 147 } 148 return !!self.BigInt64Array; 149 })(), 150 allocExportName: 'malloc', 151 deallocExportName: 'free', 152 wasmfsOpfsDir: '/opfs' 153 }, apiConfig || {}); 154 155 [ 156 // If any of these config options are functions, replace them with 157 // the result of calling that function... 158 'exports', 'memory', 'wasmfsOpfsDir' 159 ].forEach((k)=>{ 160 if('function' === typeof config[k]){ 161 config[k] = config[k](); 162 } 163 }); 164 165 /** Throws a new Error, the message of which is the concatenation 166 all args with a space between each. */ 167 const toss = (...args)=>{throw new Error(args.join(' '))}; 168 169 if(config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)){ 170 toss("config.wasmfsOpfsDir must be falsy or in the form '/dir-name'."); 171 } 172 173 /** 174 Returns true if n is a 32-bit (signed) integer, else 175 false. This is used for determining when we need to switch to 176 double-type DB operations for integer values in order to keep 177 more precision. 178 */ 179 const isInt32 = (n)=>{ 180 return ('bigint'!==typeof n /*TypeError: can't convert BigInt to number*/) 181 && !!(n===(n|0) && n<=2147483647 && n>=-2147483648); 182 }; 183 /** 184 Returns true if the given BigInt value is small enough to fit 185 into an int64 value, else false. 186 */ 187 const bigIntFits64 = function f(b){ 188 if(!f._max){ 189 f._max = BigInt("0x7fffffffffffffff"); 190 f._min = ~f._max; 191 } 192 return b >= f._min && b <= f._max; 193 }; 194 195 /** 196 Returns true if the given BigInt value is small enough to fit 197 into an int32, else false. 198 */ 199 const bigIntFits32 = (b)=>(b >= (-0x7fffffffn - 1n) && b <= 0x7fffffffn); 200 201 /** 202 Returns true if the given BigInt value is small enough to fit 203 into a double value without loss of precision, else false. 204 */ 205 const bigIntFitsDouble = function f(b){ 206 if(!f._min){ 207 f._min = Number.MIN_SAFE_INTEGER; 208 f._max = Number.MAX_SAFE_INTEGER; 209 } 210 return b >= f._min && b <= f._max; 211 }; 212 213 /** Returns v if v appears to be a TypedArray, else false. */ 214 const isTypedArray = (v)=>{ 215 return (v && v.constructor && isInt32(v.constructor.BYTES_PER_ELEMENT)) ? v : false; 216 }; 217 218 /** 219 Returns true if v appears to be one of our bind()-able 220 TypedArray types: Uint8Array or Int8Array. Support for 221 TypedArrays with element sizes >1 is TODO. 222 */ 223 const isBindableTypedArray = (v)=>{ 224 return v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT); 225 }; 226 227 /** 228 Returns true if v appears to be one of the TypedArray types 229 which is legal for holding SQL code (as opposed to binary blobs). 230 231 Currently this is the same as isBindableTypedArray() but it 232 seems likely that we'll eventually want to add Uint32Array 233 and friends to the isBindableTypedArray() list but not to the 234 isSQLableTypedArray() list. 235 */ 236 const isSQLableTypedArray = (v)=>{ 237 return v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT); 238 }; 239 240 /** Returns true if isBindableTypedArray(v) does, else throws with a message 241 that v is not a supported TypedArray value. */ 242 const affirmBindableTypedArray = (v)=>{ 243 return isBindableTypedArray(v) 244 || toss("Value is not of a supported TypedArray type."); 245 }; 246 247 const utf8Decoder = new TextDecoder('utf-8'); 248 249 /** Internal helper to use in operations which need to distinguish 250 between SharedArrayBuffer heap memory and non-shared heap. */ 251 const __SAB = ('undefined'===typeof SharedArrayBuffer) 252 ? function(){} : SharedArrayBuffer; 253 const typedArrayToString = function(arrayBuffer, begin, end){ 254 return utf8Decoder.decode( 255 (arrayBuffer.buffer instanceof __SAB) 256 ? arrayBuffer.slice(begin, end) 257 : arrayBuffer.subarray(begin, end) 258 ); 259 }; 260 261 /** 262 If v is-a Array, its join('') result is returned. If 263 isSQLableTypedArray(v) is true then typedArrayToString(v) is 264 returned. Else v is returned as-is. 265 */ 266 const flexibleString = function(v){ 267 if(isSQLableTypedArray(v)) return typedArrayToString(v); 268 else if(Array.isArray(v)) return v.join(''); 269 return v; 270 }; 271 272 /** 273 An Error subclass specifically for reporting Wasm-level malloc() 274 failure and enabling clients to unambiguously identify such 275 exceptions. 276 */ 277 class WasmAllocError extends Error { 278 constructor(...args){ 279 super(...args); 280 this.name = 'WasmAllocError'; 281 } 282 }; 283 WasmAllocError.toss = (...args)=>{ 284 throw new WasmAllocError(args.join(' ')); 285 }; 286 287 /** 288 The main sqlite3 binding API gets installed into this object, 289 mimicking the C API as closely as we can. The numerous members 290 names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as 291 possible, identically to the C-native counterparts, as documented at: 292 293 https://www.sqlite.org/c3ref/intro.html 294 295 A very few exceptions require an additional level of proxy 296 function or may otherwise require special attention in the WASM 297 environment, and all such cases are document here. Those not 298 documented here are installed as 1-to-1 proxies for their C-side 299 counterparts. 300 */ 301 const capi = { 302 /** 303 sqlite3_create_function_v2() differs from its native 304 counterpart only in the following ways: 305 306 1) The fourth argument (`eTextRep`) argument must not specify 307 any encoding other than sqlite3.SQLITE_UTF8. The JS API does not 308 currently support any other encoding and likely never 309 will. This function does not replace that argument on its own 310 because it may contain other flags. 311 312 2) Any of the four final arguments may be either WASM pointers 313 (assumed to be function pointers) or JS Functions. In the 314 latter case, each gets bound to WASM using 315 sqlite3.capi.wasm.installFunction() and that wrapper is passed 316 on to the native implementation. 317 318 The semantics of JS functions are: 319 320 xFunc: is passed `(pCtx, ...values)`. Its return value becomes 321 the new SQL function's result. 322 323 xStep: is passed `(pCtx, ...values)`. Its return value is 324 ignored. 325 326 xFinal: is passed `(pCtx)`. Its return value becomes the new 327 aggregate SQL function's result. 328 329 xDestroy: is passed `(void*)`. Its return value is ignored. The 330 pointer passed to it is the one from the 5th argument to 331 sqlite3_create_function_v2(). 332 333 Note that: 334 335 - `pCtx` in the above descriptions is a `sqlite3_context*`. At 336 least 99 times out of a hundred, that initial argument will 337 be irrelevant for JS UDF bindings, but it needs to be there 338 so that the cases where it _is_ relevant, in particular with 339 window and aggregate functions, have full access to the 340 lower-level sqlite3 APIs. 341 342 - When wrapping JS functions, the remaining arguments are passd 343 to them as positional arguments, not as an array of 344 arguments, because that allows callback definitions to be 345 more JS-idiomatic than C-like. For example `(pCtx,a,b)=>a+b` 346 is more intuitive and legible than 347 `(pCtx,args)=>args[0]+args[1]`. For cases where an array of 348 arguments would be more convenient, the callbacks simply need 349 to be declared like `(pCtx,...args)=>{...}`, in which case 350 `args` will be an array. 351 352 - If a JS wrapper throws, it gets translated to 353 sqlite3_result_error() or sqlite3_result_error_nomem(), 354 depending on whether the exception is an 355 sqlite3.WasmAllocError object or not. 356 357 - When passing on WASM function pointers, arguments are _not_ 358 converted or reformulated. They are passed on as-is in raw 359 pointer form using their native C signatures. Only JS 360 functions passed in to this routine, and thus wrapped by this 361 routine, get automatic conversions of arguments and result 362 values. The routines which perform those conversions are 363 exposed for client-side use as 364 sqlite3_create_function_v2.convertUdfArgs() and 365 sqlite3_create_function_v2.setUdfResult(). sqlite3_create_function() 366 and sqlite3_create_window_function() have those same methods. 367 368 For xFunc(), xStep(), and xFinal(): 369 370 - When called from SQL, arguments to the UDF, and its result, 371 will be converted between JS and SQL with as much fidelity as 372 is feasible, triggering an exception if a type conversion 373 cannot be determined. Some freedom is afforded to numeric 374 conversions due to friction between the JS and C worlds: 375 integers which are larger than 32 bits may be treated as 376 doubles or BigInts. 377 378 If any JS-side bound functions throw, those exceptions are 379 intercepted and converted to database-side errors with the 380 exception of xDestroy(): any exception from it is ignored, 381 possibly generating a console.error() message. Destructors 382 must not throw. 383 384 Once installed, there is currently no way to uninstall the 385 automatically-converted WASM-bound JS functions from WASM. They 386 can be uninstalled from the database as documented in the C 387 API, but this wrapper currently has no infrastructure in place 388 to also free the WASM-bound JS wrappers, effectively resulting 389 in a memory leak if the client uninstalls the UDF. Improving that 390 is a potential TODO, but removing client-installed UDFs is rare 391 in practice. If this factor is relevant for a given client, 392 they can create WASM-bound JS functions themselves, hold on to their 393 pointers, and pass the pointers in to here. Later on, they can 394 free those pointers (using `wasm.uninstallFunction()` or 395 equivalent). 396 397 C reference: https://www.sqlite.org/c3ref/create_function.html 398 399 Maintenance reminder: the ability to add new 400 WASM-accessible functions to the runtime requires that the 401 WASM build is compiled with emcc's `-sALLOW_TABLE_GROWTH` 402 flag. 403 */ 404 sqlite3_create_function_v2: function( 405 pDb, funcName, nArg, eTextRep, pApp, 406 xFunc, xStep, xFinal, xDestroy 407 ){/*installed later*/}, 408 /** 409 Equivalent to passing the same arguments to 410 sqlite3_create_function_v2(), with 0 as the final argument. 411 */ 412 sqlite3_create_function:function( 413 pDb, funcName, nArg, eTextRep, pApp, 414 xFunc, xStep, xFinal 415 ){/*installed later*/}, 416 /** 417 The sqlite3_create_window_function() JS wrapper differs from 418 its native implementation in the exact same way that 419 sqlite3_create_function_v2() does. The additional function, 420 xInverse(), is treated identically to xStep() by the wrapping 421 layer. 422 */ 423 sqlite3_create_window_function: function( 424 pDb, funcName, nArg, eTextRep, pApp, 425 xStep, xFinal, xValue, xInverse, xDestroy 426 ){/*installed later*/}, 427 /** 428 The sqlite3_prepare_v3() binding handles two different uses 429 with differing JS/WASM semantics: 430 431 1) sqlite3_prepare_v3(pDb, sqlString, -1, prepFlags, ppStmt , null) 432 433 2) sqlite3_prepare_v3(pDb, sqlPointer, sqlByteLen, prepFlags, ppStmt, sqlPointerToPointer) 434 435 Note that the SQL length argument (the 3rd argument) must, for 436 usage (1), always be negative because it must be a byte length 437 and that value is expensive to calculate from JS (where only 438 the character length of strings is readily available). It is 439 retained in this API's interface for code/documentation 440 compatibility reasons but is currently _always_ ignored. With 441 usage (2), the 3rd argument is used as-is but is is still 442 critical that the C-style input string (2nd argument) be 443 terminated with a 0 byte. 444 445 In usage (1), the 2nd argument must be of type string, 446 Uint8Array, or Int8Array (either of which is assumed to 447 hold SQL). If it is, this function assumes case (1) and 448 calls the underyling C function with the equivalent of: 449 450 (pDb, sqlAsString, -1, prepFlags, ppStmt, null) 451 452 The `pzTail` argument is ignored in this case because its 453 result is meaningless when a string-type value is passed 454 through: the string goes through another level of internal 455 conversion for WASM's sake and the result pointer would refer 456 to that transient conversion's memory, not the passed-in 457 string. 458 459 If the sql argument is not a string, it must be a _pointer_ to 460 a NUL-terminated string which was allocated in the WASM memory 461 (e.g. using capi.wasm.alloc() or equivalent). In that case, 462 the final argument may be 0/null/undefined or must be a pointer 463 to which the "tail" of the compiled SQL is written, as 464 documented for the C-side sqlite3_prepare_v3(). In case (2), 465 the underlying C function is called with the equivalent of: 466 467 (pDb, sqlAsPointer, sqlByteLen, prepFlags, ppStmt, pzTail) 468 469 It returns its result and compiled statement as documented in 470 the C API. Fetching the output pointers (5th and 6th 471 parameters) requires using `capi.wasm.getMemValue()` (or 472 equivalent) and the `pzTail` will point to an address relative to 473 the `sqlAsPointer` value. 474 475 If passed an invalid 2nd argument type, this function will 476 return SQLITE_MISUSE and sqlite3_errmsg() will contain a string 477 describing the problem. 478 479 Side-note: if given an empty string, or one which contains only 480 comments or an empty SQL expression, 0 is returned but the result 481 output pointer will be NULL. 482 */ 483 sqlite3_prepare_v3: (dbPtr, sql, sqlByteLen, prepFlags, 484 stmtPtrPtr, strPtrPtr)=>{}/*installed later*/, 485 486 /** 487 Equivalent to calling sqlite3_prapare_v3() with 0 as its 4th argument. 488 */ 489 sqlite3_prepare_v2: (dbPtr, sql, sqlByteLen, 490 stmtPtrPtr,strPtrPtr)=>{}/*installed later*/, 491 492 /** 493 This binding enables the callback argument to be a JavaScript. 494 495 If the callback is a function, then for the duration of the 496 sqlite3_exec() call, it installs a WASM-bound function which 497 acts as a proxy for the given callback. That proxy will 498 also perform a conversion of the callback's arguments from 499 `(char**)` to JS arrays of strings. However, for API 500 consistency's sake it will still honor the C-level 501 callback parameter order and will call it like: 502 503 `callback(pVoid, colCount, listOfValues, listOfColNames)` 504 505 If the callback is not a JS function then this binding performs 506 no translation of the callback, but the sql argument is still 507 converted to a WASM string for the call using the 508 "flexible-string" argument converter. 509 */ 510 sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg)=>{}/*installed later*/, 511 /** 512 Various internal-use utilities are added here as needed. They 513 are bound to an object only so that we have access to them in 514 the differently-scoped steps of the API bootstrapping 515 process. At the end of the API setup process, this object gets 516 removed. 517 */ 518 util:{ 519 affirmBindableTypedArray, flexibleString, 520 bigIntFits32, bigIntFits64, bigIntFitsDouble, 521 isBindableTypedArray, 522 isInt32, isSQLableTypedArray, isTypedArray, 523 typedArrayToString, 524 isMainWindow: ()=>{ 525 return self.window===self && self.document; 526 } 527 }, 528 529 /** 530 Holds state which are specific to the WASM-related 531 infrastructure and glue code. It is not expected that client 532 code will normally need these, but they're exposed here in case 533 it does. These APIs are _not_ to be considered an 534 official/stable part of the sqlite3 WASM API. They may change 535 as the developers' experience suggests appropriate changes. 536 537 Note that a number of members of this object are injected 538 dynamically after the api object is fully constructed, so 539 not all are documented inline here. 540 */ 541 wasm: { 542 //^^^ TODO?: move wasm from sqlite3.capi.wasm to sqlite3.wasm 543 /** 544 Emscripten APIs have a deep-seated assumption that all pointers 545 are 32 bits. We'll remain optimistic that that won't always be 546 the case and will use this constant in places where we might 547 otherwise use a hard-coded 4. 548 */ 549 ptrSizeof: config.wasmPtrSizeof || 4, 550 /** 551 The WASM IR (Intermediate Representation) value for 552 pointer-type values. It MUST refer to a value type of the 553 size described by this.ptrSizeof _or_ it may be any value 554 which ends in '*', which Emscripten's glue code internally 555 translates to i32. 556 */ 557 ptrIR: config.wasmPtrIR || "i32", 558 /** 559 True if BigInt support was enabled via (e.g.) the 560 Emscripten -sWASM_BIGINT flag, else false. When 561 enabled, certain 64-bit sqlite3 APIs are enabled which 562 are not otherwise enabled due to JS/WASM int64 563 impedence mismatches. 564 */ 565 bigIntEnabled: !!config.bigIntEnabled, 566 /** 567 The symbols exported by the WASM environment. 568 */ 569 exports: config.exports 570 || toss("Missing API config.exports (WASM module exports)."), 571 572 /** 573 When Emscripten compiles with `-sIMPORT_MEMORY`, it 574 initalizes the heap and imports it into wasm, as opposed to 575 the other way around. In this case, the memory is not 576 available via this.exports.memory. 577 */ 578 memory: config.memory || config.exports['memory'] 579 || toss("API config object requires a WebAssembly.Memory object", 580 "in either config.exports.memory (exported)", 581 "or config.memory (imported)."), 582 583 /** 584 The API's one single point of access to the WASM-side memory 585 allocator. Works like malloc(3) (and is likely bound to 586 malloc()) but throws an WasmAllocError if allocation fails. It is 587 important that any code which might pass through the sqlite3 C 588 API NOT throw and must instead return SQLITE_NOMEM (or 589 equivalent, depending on the context). 590 591 That said, very few cases in the API can result in 592 client-defined functions propagating exceptions via the C-style 593 API. Most notably, this applies ot User-defined SQL Functions 594 (UDFs) registered via sqlite3_create_function_v2(). For that 595 specific case it is recommended that all UDF creation be 596 funneled through a utility function and that a wrapper function 597 be added around the UDF which catches any exception and sets 598 the error state to OOM. (The overall complexity of registering 599 UDFs essentially requires a helper for doing so!) 600 */ 601 alloc: undefined/*installed later*/, 602 /** 603 The API's one single point of access to the WASM-side memory 604 deallocator. Works like free(3) (and is likely bound to 605 free()). 606 */ 607 dealloc: undefined/*installed later*/ 608 609 /* Many more wasm-related APIs get installed later on. */ 610 }/*wasm*/ 611 }/*capi*/; 612 613 const wasm = capi.wasm; 614 615 /** 616 wasm.alloc()'s srcTypedArray.byteLength bytes, 617 populates them with the values from the source 618 TypedArray, and returns the pointer to that memory. The 619 returned pointer must eventually be passed to 620 wasm.dealloc() to clean it up. 621 622 As a special case, to avoid further special cases where 623 this is used, if srcTypedArray.byteLength is 0, it 624 allocates a single byte and sets it to the value 625 0. Even in such cases, calls must behave as if the 626 allocated memory has exactly srcTypedArray.byteLength 627 bytes. 628 629 ACHTUNG: this currently only works for Uint8Array and 630 Int8Array types and will throw if srcTypedArray is of 631 any other type. 632 */ 633 wasm.allocFromTypedArray = function(srcTypedArray){ 634 affirmBindableTypedArray(srcTypedArray); 635 const pRet = wasm.alloc(srcTypedArray.byteLength || 1); 636 wasm.heapForSize(srcTypedArray.constructor).set(srcTypedArray.byteLength ? srcTypedArray : [0], pRet); 637 return pRet; 638 }; 639 640 const keyAlloc = config.allocExportName || 'malloc', 641 keyDealloc = config.deallocExportName || 'free'; 642 for(const key of [keyAlloc, keyDealloc]){ 643 const f = wasm.exports[key]; 644 if(!(f instanceof Function)) toss("Missing required exports[",key,"] function."); 645 } 646 647 wasm.alloc = function(n){ 648 const m = wasm.exports[keyAlloc](n); 649 if(!m) throw new WasmAllocError("Failed to allocate "+n+" bytes."); 650 return m; 651 }; 652 653 wasm.dealloc = (m)=>wasm.exports[keyDealloc](m); 654 655 /** 656 Reports info about compile-time options using 657 sqlite_compileoption_get() and sqlite3_compileoption_used(). It 658 has several distinct uses: 659 660 If optName is an array then it is expected to be a list of 661 compilation options and this function returns an object 662 which maps each such option to true or false, indicating 663 whether or not the given option was included in this 664 build. That object is returned. 665 666 If optName is an object, its keys are expected to be compilation 667 options and this function sets each entry to true or false, 668 indicating whether the compilation option was used or not. That 669 object is returned. 670 671 If passed no arguments then it returns an object mapping 672 all known compilation options to their compile-time values, 673 or boolean true if they are defined with no value. This 674 result, which is relatively expensive to compute, is cached 675 and returned for future no-argument calls. 676 677 In all other cases it returns true if the given option was 678 active when when compiling the sqlite3 module, else false. 679 680 Compile-time option names may optionally include their 681 "SQLITE_" prefix. When it returns an object of all options, 682 the prefix is elided. 683 */ 684 wasm.compileOptionUsed = function f(optName){ 685 if(!arguments.length){ 686 if(f._result) return f._result; 687 else if(!f._opt){ 688 f._rx = /^([^=]+)=(.+)/; 689 f._rxInt = /^-?\d+$/; 690 f._opt = function(opt, rv){ 691 const m = f._rx.exec(opt); 692 rv[0] = (m ? m[1] : opt); 693 rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true; 694 }; 695 } 696 const rc = {}, ov = [0,0]; 697 let i = 0, k; 698 while((k = capi.sqlite3_compileoption_get(i++))){ 699 f._opt(k,ov); 700 rc[ov[0]] = ov[1]; 701 } 702 return f._result = rc; 703 }else if(Array.isArray(optName)){ 704 const rc = {}; 705 optName.forEach((v)=>{ 706 rc[v] = capi.sqlite3_compileoption_used(v); 707 }); 708 return rc; 709 }else if('object' === typeof optName){ 710 Object.keys(optName).forEach((k)=> { 711 optName[k] = capi.sqlite3_compileoption_used(k); 712 }); 713 return optName; 714 } 715 return ( 716 'string'===typeof optName 717 ) ? !!capi.sqlite3_compileoption_used(optName) : false; 718 }/*compileOptionUsed()*/; 719 720 /** 721 Signatures for the WASM-exported C-side functions. Each entry 722 is an array with 2+ elements: 723 724 [ "c-side name", 725 "result type" (wasm.xWrap() syntax), 726 [arg types in xWrap() syntax] 727 // ^^^ this needn't strictly be an array: it can be subsequent 728 // elements instead: [x,y,z] is equivalent to x,y,z 729 ] 730 731 Note that support for the API-specific data types in the 732 result/argument type strings gets plugged in at a later phase in 733 the API initialization process. 734 */ 735 wasm.bindingSignatures = [ 736 // Please keep these sorted by function name! 737 ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"], 738 ["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*" 739 /* We should arguably write a custom wrapper which knows how 740 to handle Blob, TypedArrays, and JS strings. */ 741 ], 742 ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"], 743 ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"], 744 ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"], 745 ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"], 746 ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"], 747 ["sqlite3_bind_text","int", "sqlite3_stmt*", "int", "string", "int", "int" 748 /* We should arguably create a hand-written binding 749 which does more flexible text conversion, along the lines of 750 sqlite3_prepare_v3(). The slightly problematic part is the 751 final argument (text destructor). */ 752 ], 753 ["sqlite3_close_v2", "int", "sqlite3*"], 754 ["sqlite3_changes", "int", "sqlite3*"], 755 ["sqlite3_clear_bindings","int", "sqlite3_stmt*"], 756 ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"], 757 ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"], 758 ["sqlite3_column_count", "int", "sqlite3_stmt*"], 759 ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"], 760 ["sqlite3_column_int","int", "sqlite3_stmt*", "int"], 761 ["sqlite3_column_name","string", "sqlite3_stmt*", "int"], 762 ["sqlite3_column_text","string", "sqlite3_stmt*", "int"], 763 ["sqlite3_column_type","int", "sqlite3_stmt*", "int"], 764 ["sqlite3_compileoption_get", "string", "int"], 765 ["sqlite3_compileoption_used", "int", "string"], 766 /* sqlite3_create_function_v2() is handled separate to simplify conversion 767 of its callback argument */ 768 ["sqlite3_data_count", "int", "sqlite3_stmt*"], 769 ["sqlite3_db_filename", "string", "sqlite3*", "string"], 770 ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"], 771 ["sqlite3_db_name", "string", "sqlite3*", "int"], 772 ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"] 773 /* Careful! Short version: de/serialize() are problematic because they 774 might use a different allocator that the user for managing the 775 deserialized block. de/serialize() are ONLY safe to use with 776 sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */, 777 ["sqlite3_errmsg", "string", "sqlite3*"], 778 ["sqlite3_error_offset", "int", "sqlite3*"], 779 ["sqlite3_errstr", "string", "int"], 780 /*["sqlite3_exec", "int", "sqlite3*", "string", "*", "*", "**" 781 Handled seperately to perform translation of the callback 782 into a WASM-usable one. ],*/ 783 ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"], 784 ["sqlite3_extended_errcode", "int", "sqlite3*"], 785 ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"], 786 ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"], 787 ["sqlite3_finalize", "int", "sqlite3_stmt*"], 788 ["sqlite3_free", undefined,"*"], 789 ["sqlite3_initialize", undefined], 790 ["sqlite3_interrupt", undefined, "sqlite3*" 791 /* ^^^ we cannot actually currently support this because JS is 792 single-threaded and we don't have a portable way to access a DB 793 from 2 SharedWorkers concurrently. */], 794 ["sqlite3_libversion", "string"], 795 ["sqlite3_libversion_number", "int"], 796 ["sqlite3_malloc", "*","int"], 797 ["sqlite3_open", "int", "string", "*"], 798 ["sqlite3_open_v2", "int", "string", "*", "int", "string"], 799 /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled 800 separately due to us requiring two different sets of semantics 801 for those, depending on how their SQL argument is provided. */ 802 ["sqlite3_realloc", "*","*","int"], 803 ["sqlite3_reset", "int", "sqlite3_stmt*"], 804 ["sqlite3_result_blob",undefined, "*", "*", "int", "*"], 805 ["sqlite3_result_double",undefined, "*", "f64"], 806 ["sqlite3_result_error",undefined, "*", "string", "int"], 807 ["sqlite3_result_error_code", undefined, "*", "int"], 808 ["sqlite3_result_error_nomem", undefined, "*"], 809 ["sqlite3_result_error_toobig", undefined, "*"], 810 ["sqlite3_result_int",undefined, "*", "int"], 811 ["sqlite3_result_null",undefined, "*"], 812 ["sqlite3_result_text",undefined, "*", "string", "int", "*"], 813 ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"], 814 ["sqlite3_shutdown", undefined], 815 ["sqlite3_sourceid", "string"], 816 ["sqlite3_sql", "string", "sqlite3_stmt*"], 817 ["sqlite3_step", "int", "sqlite3_stmt*"], 818 ["sqlite3_strglob", "int", "string","string"], 819 ["sqlite3_strlike", "int", "string","string","int"], 820 ["sqlite3_trace_v2", "int", "sqlite3*", "int", "*", "*"], 821 ["sqlite3_total_changes", "int", "sqlite3*"], 822 ["sqlite3_uri_boolean", "int", "string", "string", "int"], 823 ["sqlite3_uri_key", "string", "string", "int"], 824 ["sqlite3_uri_parameter", "string", "string", "string"], 825 ["sqlite3_user_data","void*", "sqlite3_context*"], 826 ["sqlite3_value_blob", "*", "sqlite3_value*"], 827 ["sqlite3_value_bytes","int", "sqlite3_value*"], 828 ["sqlite3_value_double","f64", "sqlite3_value*"], 829 ["sqlite3_value_int","int", "sqlite3_value*"], 830 ["sqlite3_value_text", "string", "sqlite3_value*"], 831 ["sqlite3_value_type", "int", "sqlite3_value*"], 832 ["sqlite3_vfs_find", "*", "string"], 833 ["sqlite3_vfs_register", "int", "*", "int"] 834 ]/*wasm.bindingSignatures*/; 835 836 if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){ 837 /* ^^^ "the problem" is that this is an option feature and the 838 build-time function-export list does not currently take 839 optional features into account. */ 840 wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]); 841 } 842 843 /** 844 Functions which require BigInt (int64) support are separated from 845 the others because we need to conditionally bind them or apply 846 dummy impls, depending on the capabilities of the environment. 847 */ 848 wasm.bindingSignatures.int64 = [ 849 ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]], 850 ["sqlite3_changes64","i64", ["sqlite3*"]], 851 ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]], 852 ["sqlite3_malloc64", "*","i64"], 853 ["sqlite3_msize", "i64", "*"], 854 ["sqlite3_realloc64", "*","*", "i64"], 855 ["sqlite3_result_int64",undefined, "*", "i64"], 856 ["sqlite3_total_changes64", "i64", ["sqlite3*"]], 857 ["sqlite3_uri_int64", "i64", ["string", "string", "i64"]], 858 ["sqlite3_value_int64","i64", "sqlite3_value*"], 859 ]; 860 861 /** 862 Functions which are intended solely for API-internal use by the 863 WASM components, not client code. These get installed into 864 wasm. 865 866 TODO: get rid of sqlite3_wasm_vfs_unlink(). It is ill-conceived 867 and only rarely actually useful. 868 */ 869 wasm.bindingSignatures.wasm = [ 870 ["sqlite3_wasm_vfs_unlink", "int", "string"] 871 ]; 872 873 874 /** 875 sqlite3.wasm.pstack (pseudo-stack) holds a special-case 876 stack-style allocator intended only for use with _small_ data of 877 not more than (in total) a few kb in size, managed as if it were 878 stack-based. 879 880 It has only a single intended usage: 881 882 ``` 883 const stackPos = pstack.pointer; 884 try{ 885 const ptr = pstack.alloc(8); 886 // ==> pstack.pointer === ptr 887 const otherPtr = pstack.alloc(8); 888 // ==> pstack.pointer === otherPtr 889 ... 890 }finally{ 891 pstack.restore(stackPos); 892 // ==> pstack.pointer === stackPos 893 } 894 ``` 895 896 This allocator is much faster than a general-purpose one but is 897 limited to usage patterns like the one shown above. 898 899 It operates from a static range of memory which lives outside of 900 space managed by Emscripten's stack-management, so does not 901 collide with Emscripten-provided stack allocation APIs. The 902 memory lives in the WASM heap and can be used with routines such 903 as wasm.setMemValue() and any wasm.heap8u().slice(). 904 */ 905 wasm.pstack = Object.assign(Object.create(null),{ 906 /** 907 Sets the current ppstack position to the given pointer. 908 Results are undefined if the passed-in value did not come from 909 this.pointer. 910 */ 911 restore: wasm.exports.sqlite3_wasm_pstack_restore, 912 /** 913 Attempts to allocate the given number of bytes from the 914 pstack. On success, it zeroes out a block of memory of the 915 given size, adjusts the pstack pointer, and returns a pointer 916 to the memory. On error, returns throws a WasmAllocError. The 917 memory must eventually be released using restore(). 918 919 This method always adjusts the given value to be a multiple 920 of 8 bytes because failing to do so can lead to incorrect 921 results when reading and writing 64-bit values from/to the WASM 922 heap. 923 */ 924 alloc: (n)=>{ 925 return wasm.exports.sqlite3_wasm_pstack_alloc(n) 926 || WasmAllocError.toss("Could not allocate",n, 927 "bytes from the pstack."); 928 }, 929 /** 930 Allocates n chunks, each sz bytes, as a single memory block and 931 returns the addresses as an array of n element, each holding 932 the address of one chunk. 933 934 Throws a WasmAllocError if allocation fails. 935 936 Example: 937 938 ``` 939 const [p1, p2, p3] = wasm.pstack.allocChunks(3,4); 940 ``` 941 */ 942 allocChunks: (n,sz)=>{ 943 const mem = wasm.pstack.alloc(n * sz); 944 const rc = []; 945 let i = 0, offset = 0; 946 for(; i < n; offset = (sz * ++i)){ 947 rc.push(mem + offset); 948 } 949 return rc; 950 }, 951 /** 952 A convenience wrapper for allocChunks() which sizes each chunk 953 as either 8 bytes (safePtrSize is truthy) or wasm.ptrSizeof (if 954 safePtrSize is falsy). 955 956 How it returns its result differs depending on its first 957 argument: if it's 1, it returns a single pointer value. If it's 958 more than 1, it returns the same as allocChunks(). 959 960 When a returned pointers will refer to a 64-bit value, e.g. a 961 double or int64, and that value must be written or fetched, 962 e.g. using wasm.setMemValue() or wasm.getMemValue(), it is 963 important that the pointer in question be aligned to an 8-byte 964 boundary or else it will not be fetched or written properly and 965 will corrupt or read neighboring memory. 966 967 However, when all pointers involved point to "small" data, it 968 is safe to pass a falsy value to save to memory. 969 */ 970 allocPtr: (n=1,safePtrSize=true)=>{ 971 return 1===n 972 ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.ptrSizeof) 973 : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.ptrSizeof); 974 } 975 })/*wasm.pstack*/; 976 Object.defineProperties(wasm.pstack, { 977 /** 978 sqlite3.wasm.pstack.pointer resolves to the current pstack 979 position pointer. This value is intended _only_ to be saved 980 for passing to restore(). Writing to this memory, without 981 first reserving it via wasm.pstack.alloc() and friends, leads 982 to undefined results. 983 */ 984 pointer: { 985 configurable: false, iterable: true, writeable: false, 986 get: wasm.exports.sqlite3_wasm_pstack_ptr 987 //Whether or not a setter as an alternative to restore() is 988 //clearer or would just lead to confusion is unclear. 989 //set: wasm.exports.sqlite3_wasm_pstack_restore 990 }, 991 /** 992 Resolves to the total number of bytes available in the pstack, 993 including any space which is currently allocated. This value is 994 a compile-time constant. 995 */ 996 quota: { 997 configurable: false, iterable: true, writeable: false, 998 get: wasm.exports.sqlite3_wasm_pstack_quota 999 } 1000 })/*wasm.pstack properties*/; 1001 1002 /** 1003 sqlite3.wasm.pstack.remaining resolves to the amount of 1004 space remaining in the pstack. 1005 */ 1006 Object.defineProperty(wasm.pstack, 'remaining', { 1007 configurable: false, iterable: true, writeable: false, 1008 get: wasm.exports.sqlite3_wasm_pstack_remaining 1009 }); 1010 1011 /** 1012 An Error subclass specifically for reporting DB-level errors and 1013 enabling clients to unambiguously identify such exceptions. 1014 The C-level APIs never throw, but some of the higher-level 1015 C-style APIs do and the object-oriented APIs use exceptions 1016 exclusively to report errors. 1017 */ 1018 class SQLite3Error extends Error { 1019 /** 1020 Constructs this object with a message equal to all arguments 1021 concatenated with a space between each one. 1022 */ 1023 constructor(...args){ 1024 super(args.join(' ')); 1025 this.name = 'SQLite3Error'; 1026 } 1027 }; 1028 SQLite3Error.toss = (...args)=>{ 1029 throw new SQLite3Error(args.join(' ')); 1030 }; 1031 1032 /** State for sqlite3_wasmfs_opfs_dir(). */ 1033 let __persistentDir = undefined; 1034 /** 1035 If the wasm environment has a WASMFS/OPFS-backed persistent 1036 storage directory, its path is returned by this function. If it 1037 does not then it returns "" (noting that "" is a falsy value). 1038 1039 The first time this is called, this function inspects the current 1040 environment to determine whether persistence support is available 1041 and, if it is, enables it (if needed). 1042 1043 This function currently only recognizes the WASMFS/OPFS storage 1044 combination and its path refers to storage rooted in the 1045 Emscripten-managed virtual filesystem. 1046 */ 1047 capi.sqlite3_wasmfs_opfs_dir = function(){ 1048 if(undefined !== __persistentDir) return __persistentDir; 1049 // If we have no OPFS, there is no persistent dir 1050 const pdir = config.wasmfsOpfsDir; 1051 if(!pdir 1052 || !self.FileSystemHandle 1053 || !self.FileSystemDirectoryHandle 1054 || !self.FileSystemFileHandle){ 1055 return __persistentDir = ""; 1056 } 1057 try{ 1058 if(pdir && 0===wasm.xCallWrapped( 1059 'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir 1060 )){ 1061 return __persistentDir = pdir; 1062 }else{ 1063 return __persistentDir = ""; 1064 } 1065 }catch(e){ 1066 // sqlite3_wasm_init_wasmfs() is not available 1067 return __persistentDir = ""; 1068 } 1069 }; 1070 1071 /** 1072 Experimental and subject to change or removal. 1073 1074 Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a 1075 non-empty string and the given name starts with (that string + 1076 '/'), else returns false. 1077 1078 Potential (but arguable) TODO: return true if the name is one of 1079 (":localStorage:", "local", ":sessionStorage:", "session") and 1080 kvvfs is available. 1081 */ 1082 capi.sqlite3_web_filename_is_persistent = function(name){ 1083 const p = capi.sqlite3_wasmfs_opfs_dir(); 1084 return (p && name) ? name.startsWith(p+'/') : false; 1085 }; 1086 1087 // This bit is highly arguable and is incompatible with the fiddle shell. 1088 if(false && 0===wasm.exports.sqlite3_vfs_find(0)){ 1089 /* Assume that sqlite3_initialize() has not yet been called. 1090 This will be the case in an SQLITE_OS_KV build. */ 1091 wasm.exports.sqlite3_initialize(); 1092 } 1093 1094 /** 1095 Given an `sqlite3*`, an sqlite3_vfs name, and an optional db 1096 name, returns a truthy value (see below) if that db handle uses 1097 that VFS, else returns false. If pDb is falsy then the 3rd 1098 argument is ignored and this function returns a truthy value if 1099 the default VFS name matches that of the 2nd argument. Results 1100 are undefined if pDb is truthy but refers to an invalid 1101 pointer. The 3rd argument specifies the database name of the 1102 given database connection to check, defaulting to the main db. 1103 1104 The 2nd and 3rd arguments may either be a JS string or a C-string 1105 allocated from the wasm environment. 1106 1107 The truthy value it returns is a pointer to the `sqlite3_vfs` 1108 object. 1109 1110 To permit safe use of this function from APIs which may be called 1111 via the C stack (like SQL UDFs), this function does not throw: if 1112 bad arguments cause a conversion error when passing into 1113 wasm-space, false is returned. 1114 */ 1115 capi.sqlite3_web_db_uses_vfs = function(pDb,vfsName,dbName="main"){ 1116 try{ 1117 const pK = capi.sqlite3_vfs_find(vfsName); 1118 if(!pK) return false; 1119 else if(!pDb){ 1120 return capi.sqlite3_vfs_find(0)===pK ? pK : false; 1121 } 1122 const ppVfs = wasm.allocPtr(); 1123 try{ 1124 return ( 1125 (0===capi.sqlite3_file_control( 1126 pDb, dbName, capi.SQLITE_FCNTL_VFS_POINTER, ppVfs 1127 )) && (wasm.getPtrValue(ppVfs) === pK) 1128 ) ? pK : false; 1129 }finally{ 1130 wasm.dealloc(ppVfs); 1131 } 1132 }catch(e){ 1133 /* Ignore - probably bad args to a wasm-bound function. */ 1134 return false; 1135 } 1136 }; 1137 1138 /** 1139 Returns an array of the names of all currently-registered sqlite3 1140 VFSes. 1141 */ 1142 capi.sqlite3_web_vfs_list = function(){ 1143 const rc = []; 1144 let pVfs = capi.sqlite3_vfs_find(0); 1145 while(pVfs){ 1146 const oVfs = new capi.sqlite3_vfs(pVfs); 1147 rc.push(wasm.cstringToJs(oVfs.$zName)); 1148 pVfs = oVfs.$pNext; 1149 oVfs.dispose(); 1150 } 1151 return rc; 1152 }; 1153 1154 /** 1155 Serializes the given `sqlite3*` pointer to a Uint8Array, as per 1156 sqlite3_serialize(). On success it returns a Uint8Array. On 1157 error it throws with a description of the problem. 1158 */ 1159 capi.sqlite3_web_db_export = function(pDb){ 1160 if(!pDb) toss('Invalid sqlite3* argument.'); 1161 const wasm = wasm; 1162 if(!wasm.bigIntEnabled) toss('BigInt64 support is not enabled.'); 1163 const stack = wasm.pstack.pointer; 1164 let pOut; 1165 try{ 1166 const pSize = wasm.pstack.alloc(8/*i64*/ + wasm.ptrSizeof); 1167 const ppOut = pSize + 8; 1168 /** 1169 Maintenance reminder, since this cost a full hour of grief 1170 and confusion: if the order of pSize/ppOut are reversed in 1171 that memory block, fetching the value of pSize after the 1172 export reads a garbage size because it's not on an 8-byte 1173 memory boundary! 1174 */ 1175 let rc = wasm.exports.sqlite3_wasm_db_serialize( 1176 pDb, ppOut, pSize, 0 1177 ); 1178 if(rc){ 1179 toss("Database serialization failed with code", 1180 sqlite3.capi.sqlite3_web_rc_str(rc)); 1181 } 1182 pOut = wasm.getPtrValue(ppOut); 1183 const nOut = wasm.getMemValue(pSize, 'i64'); 1184 rc = nOut 1185 ? wasm.heap8u().slice(pOut, pOut + Number(nOut)) 1186 : new Uint8Array(); 1187 return rc; 1188 }catch(e){ 1189 console.error('internal error?',e); 1190 throw w; 1191 }finally{ 1192 if(pOut) wasm.exports.sqlite3_free(pOut); 1193 wasm.pstack.restore(stack); 1194 } 1195 }; 1196 1197 if( capi.util.isMainWindow() ){ 1198 /* Features specific to the main window thread... */ 1199 1200 /** 1201 Internal helper for sqlite3_web_kvvfs_clear() and friends. 1202 Its argument should be one of ('local','session',''). 1203 */ 1204 const __kvvfsInfo = function(which){ 1205 const rc = Object.create(null); 1206 rc.prefix = 'kvvfs-'+which; 1207 rc.stores = []; 1208 if('session'===which || ''===which) rc.stores.push(self.sessionStorage); 1209 if('local'===which || ''===which) rc.stores.push(self.localStorage); 1210 return rc; 1211 }; 1212 1213 /** 1214 Clears all storage used by the kvvfs DB backend, deleting any 1215 DB(s) stored there. Its argument must be either 'session', 1216 'local', or ''. In the first two cases, only sessionStorage 1217 resp. localStorage is cleared. If it's an empty string (the 1218 default) then both are cleared. Only storage keys which match 1219 the pattern used by kvvfs are cleared: any other client-side 1220 data are retained. 1221 1222 This function is only available in the main window thread. 1223 1224 Returns the number of entries cleared. 1225 */ 1226 capi.sqlite3_web_kvvfs_clear = function(which=''){ 1227 let rc = 0; 1228 const kvinfo = __kvvfsInfo(which); 1229 kvinfo.stores.forEach((s)=>{ 1230 const toRm = [] /* keys to remove */; 1231 let i; 1232 for( i = 0; i < s.length; ++i ){ 1233 const k = s.key(i); 1234 if(k.startsWith(kvinfo.prefix)) toRm.push(k); 1235 } 1236 toRm.forEach((kk)=>s.removeItem(kk)); 1237 rc += toRm.length; 1238 }); 1239 return rc; 1240 }; 1241 1242 /** 1243 This routine guesses the approximate amount of 1244 window.localStorage and/or window.sessionStorage in use by the 1245 kvvfs database backend. Its argument must be one of 1246 ('session', 'local', ''). In the first two cases, only 1247 sessionStorage resp. localStorage is counted. If it's an empty 1248 string (the default) then both are counted. Only storage keys 1249 which match the pattern used by kvvfs are counted. The returned 1250 value is the "length" value of every matching key and value, 1251 noting that JavaScript stores each character in 2 bytes. 1252 1253 Note that the returned size is not authoritative from the 1254 perspective of how much data can fit into localStorage and 1255 sessionStorage, as the precise algorithms for determining 1256 those limits are unspecified and may include per-entry 1257 overhead invisible to clients. 1258 */ 1259 capi.sqlite3_web_kvvfs_size = function(which=''){ 1260 let sz = 0; 1261 const kvinfo = __kvvfsInfo(which); 1262 kvinfo.stores.forEach((s)=>{ 1263 let i; 1264 for(i = 0; i < s.length; ++i){ 1265 const k = s.key(i); 1266 if(k.startsWith(kvinfo.prefix)){ 1267 sz += k.length; 1268 sz += s.getItem(k).length; 1269 } 1270 } 1271 }); 1272 return sz * 2 /* because JS uses 2-byte char encoding */; 1273 }; 1274 1275 }/* main-window-only bits */ 1276 1277 1278 /* The remainder of the API will be set up in later steps. */ 1279 const sqlite3 = { 1280 WasmAllocError: WasmAllocError, 1281 SQLite3Error: SQLite3Error, 1282 capi, 1283 config, 1284 /** 1285 Holds the version info of the sqlite3 source tree from which 1286 the generated sqlite3-api.js gets built. Note that its version 1287 may well differ from that reported by sqlite3_libversion(), but 1288 that should be considered a source file mismatch, as the JS and 1289 WASM files are intended to be built and distributed together. 1290 1291 This object is initially a placeholder which gets replaced by a 1292 build-generated object. 1293 */ 1294 version: Object.create(null), 1295 /** 1296 Performs any optional asynchronous library-level initialization 1297 which might be required. This function returns a Promise which 1298 resolves to the sqlite3 namespace object. Any error in the 1299 async init will be fatal to the init as a whole, but init 1300 routines are themselves welcome to install dummy catch() 1301 handlers which are not fatal if their failure should be 1302 considered non-fatal. If called more than once, the second and 1303 subsequent calls are no-ops which return a pre-resolved 1304 Promise. 1305 1306 Ideally this function is called as part of the Promise chain 1307 which handles the loading and bootstrapping of the API. If not 1308 then it must be called by client-level code, which must not use 1309 the library until the returned promise resolves. 1310 1311 Bug: if called while a prior call is still resolving, the 2nd 1312 call will resolve prematurely, before the 1st call has finished 1313 resolving. The current build setup precludes that possibility, 1314 so it's only a hypothetical problem if/when this function 1315 ever needs to be invoked by clients. 1316 1317 In Emscripten-based builds, this function is called 1318 automatically and deleted from this object. 1319 */ 1320 asyncPostInit: async function(){ 1321 let lip = sqlite3ApiBootstrap.initializersAsync; 1322 delete sqlite3ApiBootstrap.initializersAsync; 1323 if(!lip || !lip.length) return Promise.resolve(sqlite3); 1324 // Is it okay to resolve these in parallel or do we need them 1325 // to resolve in order? We currently only have 1, so it 1326 // makes no difference. 1327 lip = lip.map((f)=>{ 1328 const p = (f instanceof Promise) ? f : f(sqlite3); 1329 return p.catch((e)=>{ 1330 console.error("an async sqlite3 initializer failed:",e); 1331 throw e; 1332 }); 1333 }); 1334 //let p = lip.shift(); 1335 //while(lip.length) p = p.then(lip.shift()); 1336 //return p.then(()=>sqlite3); 1337 return Promise.all(lip).then(()=>sqlite3); 1338 } 1339 }; 1340 try{ 1341 sqlite3ApiBootstrap.initializers.forEach((f)=>{ 1342 f(sqlite3); 1343 }); 1344 }catch(e){ 1345 /* If we don't report this here, it can get completely swallowed 1346 up and disappear into the abyss of Promises and Workers. */ 1347 console.error("sqlite3 bootstrap initializer threw:",e); 1348 throw e; 1349 } 1350 delete sqlite3ApiBootstrap.initializers; 1351 sqlite3ApiBootstrap.sqlite3 = sqlite3; 1352 return sqlite3; 1353}/*sqlite3ApiBootstrap()*/; 1354/** 1355 self.sqlite3ApiBootstrap.initializers is an internal detail used by 1356 the various pieces of the sqlite3 API's amalgamation process. It 1357 must not be modified by client code except when plugging such code 1358 into the amalgamation process. 1359 1360 Each component of the amalgamation is expected to append a function 1361 to this array. When sqlite3ApiBootstrap() is called for the first 1362 time, each such function will be called (in their appended order) 1363 and passed the sqlite3 namespace object, into which they can install 1364 their features (noting that most will also require that certain 1365 features alread have been installed). At the end of that process, 1366 this array is deleted. 1367 1368 Note that the order of insertion into this array is significant for 1369 some pieces. e.g. sqlite3.capi and sqlite3.capi.wasm cannot be fully 1370 utilized until the whwasmutil.js part is plugged in via 1371 sqlite3-api-glue.js. 1372*/ 1373self.sqlite3ApiBootstrap.initializers = []; 1374/** 1375 self.sqlite3ApiBootstrap.initializersAsync is an internal detail 1376 used by the sqlite3 API's amalgamation process. It must not be 1377 modified by client code except when plugging such code into the 1378 amalgamation process. 1379 1380 The counterpart of self.sqlite3ApiBootstrap.initializers, 1381 specifically for initializers which are asynchronous. All entries in 1382 this list must be either async functions, non-async functions which 1383 return a Promise, or a Promise. Each function in the list is called 1384 with the sqlite3 ojbect as its only argument. 1385 1386 The resolved value of any Promise is ignored and rejection will kill 1387 the asyncPostInit() process (at an indeterminate point because all 1388 of them are run asynchronously in parallel). 1389 1390 This list is not processed until the client calls 1391 sqlite3.asyncPostInit(). This means, for example, that intializers 1392 added to self.sqlite3ApiBootstrap.initializers may push entries to 1393 this list. 1394*/ 1395self.sqlite3ApiBootstrap.initializersAsync = []; 1396/** 1397 Client code may assign sqlite3ApiBootstrap.defaultConfig an 1398 object-type value before calling sqlite3ApiBootstrap() (without 1399 arguments) in order to tell that call to use this object as its 1400 default config value. The intention of this is to provide 1401 downstream clients with a reasonably flexible approach for plugging in 1402 an environment-suitable configuration without having to define a new 1403 global-scope symbol. 1404*/ 1405self.sqlite3ApiBootstrap.defaultConfig = Object.create(null); 1406/** 1407 Placeholder: gets installed by the first call to 1408 self.sqlite3ApiBootstrap(). However, it is recommended that the 1409 caller of sqlite3ApiBootstrap() capture its return value and delete 1410 self.sqlite3ApiBootstrap after calling it. It returns the same 1411 value which will be stored here. 1412*/ 1413self.sqlite3ApiBootstrap.sqlite3 = undefined; 1414