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 apiConfig = apiConfig || {}; 140 const config = Object.create(null); 141 { 142 const configDefaults = { 143 exports: undefined, 144 memory: undefined, 145 bigIntEnabled: (()=>{ 146 if('undefined'!==typeof Module){ 147 /* Emscripten module will contain HEAPU64 when built with 148 -sWASM_BIGINT=1, else it will not. */ 149 return !!Module.HEAPU64; 150 } 151 return !!self.BigInt64Array; 152 })(), 153 allocExportName: 'malloc', 154 deallocExportName: 'free', 155 wasmfsOpfsDir: '/opfs' 156 }; 157 Object.keys(configDefaults).forEach(function(k){ 158 config[k] = Object.getOwnPropertyDescriptor(apiConfig, k) 159 ? apiConfig[k] : configDefaults[k]; 160 }); 161 // Copy over any properties apiConfig defines but configDefaults does not... 162 Object.keys(apiConfig).forEach(function(k){ 163 if(!Object.getOwnPropertyDescriptor(config, k)){ 164 config[k] = apiConfig[k]; 165 } 166 }); 167 } 168 169 [ 170 // If any of these config options are functions, replace them with 171 // the result of calling that function... 172 'exports', 'memory', 'wasmfsOpfsDir' 173 ].forEach((k)=>{ 174 if('function' === typeof config[k]){ 175 config[k] = config[k](); 176 } 177 }); 178 179 /** Throws a new Error, the message of which is the concatenation 180 all args with a space between each. */ 181 const toss = (...args)=>{throw new Error(args.join(' '))}; 182 183 if(config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)){ 184 toss("config.wasmfsOpfsDir must be falsy or in the form '/dir-name'."); 185 } 186 187 /** 188 Returns true if n is a 32-bit (signed) integer, else 189 false. This is used for determining when we need to switch to 190 double-type DB operations for integer values in order to keep 191 more precision. 192 */ 193 const isInt32 = function(n){ 194 return ('bigint'!==typeof n /*TypeError: can't convert BigInt to number*/) 195 && !!(n===(n|0) && n<=2147483647 && n>=-2147483648); 196 }; 197 198 /** Returns v if v appears to be a TypedArray, else false. */ 199 const isTypedArray = (v)=>{ 200 return (v && v.constructor && isInt32(v.constructor.BYTES_PER_ELEMENT)) ? v : false; 201 }; 202 203 /** 204 Returns true if v appears to be one of our bind()-able 205 TypedArray types: Uint8Array or Int8Array. Support for 206 TypedArrays with element sizes >1 is TODO. 207 */ 208 const isBindableTypedArray = (v)=>{ 209 return v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT); 210 }; 211 212 /** 213 Returns true if v appears to be one of the TypedArray types 214 which is legal for holding SQL code (as opposed to binary blobs). 215 216 Currently this is the same as isBindableTypedArray() but it 217 seems likely that we'll eventually want to add Uint32Array 218 and friends to the isBindableTypedArray() list but not to the 219 isSQLableTypedArray() list. 220 */ 221 const isSQLableTypedArray = (v)=>{ 222 return v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT); 223 }; 224 225 /** Returns true if isBindableTypedArray(v) does, else throws with a message 226 that v is not a supported TypedArray value. */ 227 const affirmBindableTypedArray = (v)=>{ 228 return isBindableTypedArray(v) 229 || toss("Value is not of a supported TypedArray type."); 230 }; 231 232 const utf8Decoder = new TextDecoder('utf-8'); 233 234 /** Internal helper to use in operations which need to distinguish 235 between SharedArrayBuffer heap memory and non-shared heap. */ 236 const __SAB = ('undefined'===typeof SharedArrayBuffer) 237 ? function(){} : SharedArrayBuffer; 238 const typedArrayToString = function(arrayBuffer, begin, end){ 239 return utf8Decoder.decode( 240 (arrayBuffer.buffer instanceof __SAB) 241 ? arrayBuffer.slice(begin, end) 242 : arrayBuffer.subarray(begin, end) 243 ); 244 }; 245 246 /** 247 If v is-a Array, its join('') result is returned. If 248 isSQLableTypedArray(v) then typedArrayToString(v) is 249 returned. Else v is returned as-is. 250 */ 251 const arrayToString = function(v){ 252 if(isSQLableTypedArray(v)) return typedArrayToString(v); 253 else if(Array.isArray(v)) return v.join(''); 254 return v; 255 }; 256 257 /** 258 An Error subclass specifically for reporting Wasm-level malloc() 259 failure and enabling clients to unambiguously identify such 260 exceptions. 261 */ 262 class WasmAllocError extends Error { 263 constructor(...args){ 264 super(...args); 265 this.name = 'WasmAllocError'; 266 } 267 }; 268 WasmAllocError.toss = (...args)=>{ 269 throw new WasmAllocError(args.join(' ')); 270 }; 271 272 /** 273 The main sqlite3 binding API gets installed into this object, 274 mimicking the C API as closely as we can. The numerous members 275 names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as 276 possible, identically to the C-native counterparts, as documented at: 277 278 https://www.sqlite.org/c3ref/intro.html 279 280 A very few exceptions require an additional level of proxy 281 function or may otherwise require special attention in the WASM 282 environment, and all such cases are document here. Those not 283 documented here are installed as 1-to-1 proxies for their C-side 284 counterparts. 285 */ 286 const capi = { 287 /** 288 When using sqlite3_open_v2() it is important to keep the following 289 in mind: 290 291 https://www.sqlite.org/c3ref/open.html 292 293 - The flags for use with its 3rd argument are installed in this 294 object using their C-side names, e.g. SQLITE_OPEN_CREATE. 295 296 - If the combination of flags passed to it are invalid, 297 behavior is undefined. Thus is is never okay to call this 298 with fewer than 3 arguments, as JS will default the 299 missing arguments to `undefined`, which will result in a 300 flag value of 0. Most of the available SQLITE_OPEN_xxx 301 flags are meaningless in the WASM build, e.g. the mutext- 302 and cache-related flags, but they are retained in this 303 API for consistency's sake. 304 305 - The final argument to this function specifies the VFS to use, 306 which is largely (but not entirely!) meaningless in the WASM 307 environment. It may be null, undefined, or 0 to denote the 308 default. 309 */ 310 sqlite3_open_v2: function(filename,dbPtrPtr,flags,vfsStr){}/*installed later*/, 311 /** 312 The sqlite3_prepare_v3() binding handles two different uses 313 with differing JS/WASM semantics: 314 315 1) sqlite3_prepare_v3(pDb, sqlString, -1, prepFlags, ppStmt , null) 316 317 2) sqlite3_prepare_v3(pDb, sqlPointer, sqlByteLen, prepFlags, ppStmt, sqlPointerToPointer) 318 319 Note that the SQL length argument (the 3rd argument) must, for 320 usage (1), always be negative because it must be a byte length 321 and that value is expensive to calculate from JS (where only 322 the character length of strings is readily available). It is 323 retained in this API's interface for code/documentation 324 compatibility reasons but is currently _always_ ignored. With 325 usage (2), the 3rd argument is used as-is but is is still 326 critical that the C-style input string (2nd argument) be 327 terminated with a 0 byte. 328 329 In usage (1), the 2nd argument must be of type string, 330 Uint8Array, or Int8Array (either of which is assumed to 331 hold SQL). If it is, this function assumes case (1) and 332 calls the underyling C function with the equivalent of: 333 334 (pDb, sqlAsString, -1, prepFlags, ppStmt, null) 335 336 The `pzTail` argument is ignored in this case because its 337 result is meaningless when a string-type value is passed 338 through: the string goes through another level of internal 339 conversion for WASM's sake and the result pointer would refer 340 to that transient conversion's memory, not the passed-in 341 string. 342 343 If the sql argument is not a string, it must be a _pointer_ to 344 a NUL-terminated string which was allocated in the WASM memory 345 (e.g. using capi.wasm.alloc() or equivalent). In that case, 346 the final argument may be 0/null/undefined or must be a pointer 347 to which the "tail" of the compiled SQL is written, as 348 documented for the C-side sqlite3_prepare_v3(). In case (2), 349 the underlying C function is called with the equivalent of: 350 351 (pDb, sqlAsPointer, sqlByteLen, prepFlags, ppStmt, pzTail) 352 353 It returns its result and compiled statement as documented in 354 the C API. Fetching the output pointers (5th and 6th 355 parameters) requires using `capi.wasm.getMemValue()` (or 356 equivalent) and the `pzTail` will point to an address relative to 357 the `sqlAsPointer` value. 358 359 If passed an invalid 2nd argument type, this function will 360 return SQLITE_MISUSE and sqlite3_errmsg() will contain a string 361 describing the problem. 362 363 Side-note: if given an empty string, or one which contains only 364 comments or an empty SQL expression, 0 is returned but the result 365 output pointer will be NULL. 366 */ 367 sqlite3_prepare_v3: (dbPtr, sql, sqlByteLen, prepFlags, 368 stmtPtrPtr, strPtrPtr)=>{}/*installed later*/, 369 370 /** 371 Equivalent to calling sqlite3_prapare_v3() with 0 as its 4th argument. 372 */ 373 sqlite3_prepare_v2: (dbPtr, sql, sqlByteLen, 374 stmtPtrPtr,strPtrPtr)=>{}/*installed later*/, 375 376 /** 377 This binding enables the callback argument to be a JavaScript. 378 379 If the callback is a function, then for the duration of the 380 sqlite3_exec() call, it installs a WASM-bound function which 381 acts as a proxy for the given callback. That proxy will 382 also perform a conversion of the callback's arguments from 383 `(char**)` to JS arrays of strings. However, for API 384 consistency's sake it will still honor the C-level 385 callback parameter order and will call it like: 386 387 `callback(pVoid, colCount, listOfValues, listOfColNames)` 388 389 If the callback is not a JS function then this binding performs 390 no translation of the callback, but the sql argument is still 391 converted to a WASM string for the call using the 392 "flexible-string" argument converter. 393 */ 394 sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg)=>{}/*installed later*/, 395 /** 396 Various internal-use utilities are added here as needed. They 397 are bound to an object only so that we have access to them in 398 the differently-scoped steps of the API bootstrapping 399 process. At the end of the API setup process, this object gets 400 removed. 401 */ 402 util:{ 403 affirmBindableTypedArray, arrayToString, isBindableTypedArray, 404 isInt32, isSQLableTypedArray, isTypedArray, 405 typedArrayToString, 406 isMainWindow: ()=>{ 407 return self.window===self && self.document; 408 } 409 }, 410 411 /** 412 Holds state which are specific to the WASM-related 413 infrastructure and glue code. It is not expected that client 414 code will normally need these, but they're exposed here in case 415 it does. These APIs are _not_ to be considered an 416 official/stable part of the sqlite3 WASM API. They may change 417 as the developers' experience suggests appropriate changes. 418 419 Note that a number of members of this object are injected 420 dynamically after the api object is fully constructed, so 421 not all are documented inline here. 422 */ 423 wasm: { 424 //^^^ TODO?: move wasm from sqlite3.capi.wasm to sqlite3.wasm 425 /** 426 Emscripten APIs have a deep-seated assumption that all pointers 427 are 32 bits. We'll remain optimistic that that won't always be 428 the case and will use this constant in places where we might 429 otherwise use a hard-coded 4. 430 */ 431 ptrSizeof: config.wasmPtrSizeof || 4, 432 /** 433 The WASM IR (Intermediate Representation) value for 434 pointer-type values. It MUST refer to a value type of the 435 size described by this.ptrSizeof _or_ it may be any value 436 which ends in '*', which Emscripten's glue code internally 437 translates to i32. 438 */ 439 ptrIR: config.wasmPtrIR || "i32", 440 /** 441 True if BigInt support was enabled via (e.g.) the 442 Emscripten -sWASM_BIGINT flag, else false. When 443 enabled, certain 64-bit sqlite3 APIs are enabled which 444 are not otherwise enabled due to JS/WASM int64 445 impedence mismatches. 446 */ 447 bigIntEnabled: !!config.bigIntEnabled, 448 /** 449 The symbols exported by the WASM environment. 450 */ 451 exports: config.exports 452 || toss("Missing API config.exports (WASM module exports)."), 453 454 /** 455 When Emscripten compiles with `-sIMPORT_MEMORY`, it 456 initalizes the heap and imports it into wasm, as opposed to 457 the other way around. In this case, the memory is not 458 available via this.exports.memory. 459 */ 460 memory: config.memory || config.exports['memory'] 461 || toss("API config object requires a WebAssembly.Memory object", 462 "in either config.exports.memory (exported)", 463 "or config.memory (imported)."), 464 465 /** 466 The API's one single point of access to the WASM-side memory 467 allocator. Works like malloc(3) (and is likely bound to 468 malloc()) but throws an WasmAllocError if allocation fails. It is 469 important that any code which might pass through the sqlite3 C 470 API NOT throw and must instead return SQLITE_NOMEM (or 471 equivalent, depending on the context). 472 473 That said, very few cases in the API can result in 474 client-defined functions propagating exceptions via the C-style 475 API. Most notably, this applies ot User-defined SQL Functions 476 (UDFs) registered via sqlite3_create_function_v2(). For that 477 specific case it is recommended that all UDF creation be 478 funneled through a utility function and that a wrapper function 479 be added around the UDF which catches any exception and sets 480 the error state to OOM. (The overall complexity of registering 481 UDFs essentially requires a helper for doing so!) 482 */ 483 alloc: undefined/*installed later*/, 484 /** 485 The API's one single point of access to the WASM-side memory 486 deallocator. Works like free(3) (and is likely bound to 487 free()). 488 */ 489 dealloc: undefined/*installed later*/ 490 491 /* Many more wasm-related APIs get installed later on. */ 492 }/*wasm*/ 493 }/*capi*/; 494 495 /** 496 capi.wasm.alloc()'s srcTypedArray.byteLength bytes, 497 populates them with the values from the source 498 TypedArray, and returns the pointer to that memory. The 499 returned pointer must eventually be passed to 500 capi.wasm.dealloc() to clean it up. 501 502 As a special case, to avoid further special cases where 503 this is used, if srcTypedArray.byteLength is 0, it 504 allocates a single byte and sets it to the value 505 0. Even in such cases, calls must behave as if the 506 allocated memory has exactly srcTypedArray.byteLength 507 bytes. 508 509 ACHTUNG: this currently only works for Uint8Array and 510 Int8Array types and will throw if srcTypedArray is of 511 any other type. 512 */ 513 capi.wasm.allocFromTypedArray = function(srcTypedArray){ 514 affirmBindableTypedArray(srcTypedArray); 515 const pRet = this.alloc(srcTypedArray.byteLength || 1); 516 this.heapForSize(srcTypedArray.constructor).set(srcTypedArray.byteLength ? srcTypedArray : [0], pRet); 517 return pRet; 518 }.bind(capi.wasm); 519 520 const keyAlloc = config.allocExportName || 'malloc', 521 keyDealloc = config.deallocExportName || 'free'; 522 for(const key of [keyAlloc, keyDealloc]){ 523 const f = capi.wasm.exports[key]; 524 if(!(f instanceof Function)) toss("Missing required exports[",key,"] function."); 525 } 526 527 capi.wasm.alloc = function(n){ 528 const m = this.exports[keyAlloc](n); 529 if(!m) throw new WasmAllocError("Failed to allocate "+n+" bytes."); 530 return m; 531 }.bind(capi.wasm) 532 533 capi.wasm.dealloc = (m)=>capi.wasm.exports[keyDealloc](m); 534 535 /** 536 Reports info about compile-time options using 537 sqlite_compileoption_get() and sqlite3_compileoption_used(). It 538 has several distinct uses: 539 540 If optName is an array then it is expected to be a list of 541 compilation options and this function returns an object 542 which maps each such option to true or false, indicating 543 whether or not the given option was included in this 544 build. That object is returned. 545 546 If optName is an object, its keys are expected to be compilation 547 options and this function sets each entry to true or false, 548 indicating whether the compilation option was used or not. That 549 object is returned. 550 551 If passed no arguments then it returns an object mapping 552 all known compilation options to their compile-time values, 553 or boolean true if they are defined with no value. This 554 result, which is relatively expensive to compute, is cached 555 and returned for future no-argument calls. 556 557 In all other cases it returns true if the given option was 558 active when when compiling the sqlite3 module, else false. 559 560 Compile-time option names may optionally include their 561 "SQLITE_" prefix. When it returns an object of all options, 562 the prefix is elided. 563 */ 564 capi.wasm.compileOptionUsed = function f(optName){ 565 if(!arguments.length){ 566 if(f._result) return f._result; 567 else if(!f._opt){ 568 f._rx = /^([^=]+)=(.+)/; 569 f._rxInt = /^-?\d+$/; 570 f._opt = function(opt, rv){ 571 const m = f._rx.exec(opt); 572 rv[0] = (m ? m[1] : opt); 573 rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true; 574 }; 575 } 576 const rc = {}, ov = [0,0]; 577 let i = 0, k; 578 while((k = capi.sqlite3_compileoption_get(i++))){ 579 f._opt(k,ov); 580 rc[ov[0]] = ov[1]; 581 } 582 return f._result = rc; 583 }else if(Array.isArray(optName)){ 584 const rc = {}; 585 optName.forEach((v)=>{ 586 rc[v] = capi.sqlite3_compileoption_used(v); 587 }); 588 return rc; 589 }else if('object' === typeof optName){ 590 Object.keys(optName).forEach((k)=> { 591 optName[k] = capi.sqlite3_compileoption_used(k); 592 }); 593 return optName; 594 } 595 return ( 596 'string'===typeof optName 597 ) ? !!capi.sqlite3_compileoption_used(optName) : false; 598 }/*compileOptionUsed()*/; 599 600 /** 601 Signatures for the WASM-exported C-side functions. Each entry 602 is an array with 2+ elements: 603 604 [ "c-side name", 605 "result type" (capi.wasm.xWrap() syntax), 606 [arg types in xWrap() syntax] 607 // ^^^ this needn't strictly be an array: it can be subsequent 608 // elements instead: [x,y,z] is equivalent to x,y,z 609 ] 610 611 Note that support for the API-specific data types in the 612 result/argument type strings gets plugged in at a later phase in 613 the API initialization process. 614 */ 615 capi.wasm.bindingSignatures = [ 616 // Please keep these sorted by function name! 617 ["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*" 618 /* We should arguably write a custom wrapper which knows how 619 to handle Blob, TypedArrays, and JS strings. */ 620 ], 621 ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"], 622 ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"], 623 ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"], 624 ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"], 625 ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"], 626 ["sqlite3_bind_text","int", "sqlite3_stmt*", "int", "string", "int", "int" 627 /* We should arguably create a hand-written binding 628 which does more flexible text conversion, along the lines of 629 sqlite3_prepare_v3(). The slightly problematic part is the 630 final argument (text destructor). */ 631 ], 632 ["sqlite3_close_v2", "int", "sqlite3*"], 633 ["sqlite3_changes", "int", "sqlite3*"], 634 ["sqlite3_clear_bindings","int", "sqlite3_stmt*"], 635 ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"], 636 ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"], 637 ["sqlite3_column_count", "int", "sqlite3_stmt*"], 638 ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"], 639 ["sqlite3_column_int","int", "sqlite3_stmt*", "int"], 640 ["sqlite3_column_name","string", "sqlite3_stmt*", "int"], 641 ["sqlite3_column_text","string", "sqlite3_stmt*", "int"], 642 ["sqlite3_column_type","int", "sqlite3_stmt*", "int"], 643 ["sqlite3_compileoption_get", "string", "int"], 644 ["sqlite3_compileoption_used", "int", "string"], 645 ["sqlite3_create_function_v2", "int", 646 "sqlite3*", "string", "int", "int", "*", "*", "*", "*", "*"], 647 ["sqlite3_data_count", "int", "sqlite3_stmt*"], 648 ["sqlite3_db_filename", "string", "sqlite3*", "string"], 649 ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"], 650 ["sqlite3_db_name", "string", "sqlite3*", "int"], 651 ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"] 652 /* Careful! Short version: de/serialize() are problematic because they 653 might use a different allocator that the user for managing the 654 deserialized block. de/serialize() are ONLY safe to use with 655 sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */, 656 ["sqlite3_errmsg", "string", "sqlite3*"], 657 ["sqlite3_error_offset", "int", "sqlite3*"], 658 ["sqlite3_errstr", "string", "int"], 659 /*["sqlite3_exec", "int", "sqlite3*", "string", "*", "*", "**" 660 Handled seperately to perform translation of the callback 661 into a WASM-usable one. ],*/ 662 ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"], 663 ["sqlite3_extended_errcode", "int", "sqlite3*"], 664 ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"], 665 ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"], 666 ["sqlite3_finalize", "int", "sqlite3_stmt*"], 667 ["sqlite3_free", undefined,"*"], 668 ["sqlite3_initialize", undefined], 669 ["sqlite3_interrupt", undefined, "sqlite3*" 670 /* ^^^ we cannot actually currently support this because JS is 671 single-threaded and we don't have a portable way to access a DB 672 from 2 SharedWorkers concurrently. */], 673 ["sqlite3_libversion", "string"], 674 ["sqlite3_libversion_number", "int"], 675 ["sqlite3_malloc", "*","int"], 676 ["sqlite3_open", "int", "string", "*"], 677 ["sqlite3_open_v2", "int", "string", "*", "int", "string"], 678 /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled 679 separately due to us requiring two different sets of semantics 680 for those, depending on how their SQL argument is provided. */ 681 ["sqlite3_realloc", "*","*","int"], 682 ["sqlite3_reset", "int", "sqlite3_stmt*"], 683 ["sqlite3_result_blob",undefined, "*", "*", "int", "*"], 684 ["sqlite3_result_double",undefined, "*", "f64"], 685 ["sqlite3_result_error",undefined, "*", "string", "int"], 686 ["sqlite3_result_error_code", undefined, "*", "int"], 687 ["sqlite3_result_error_nomem", undefined, "*"], 688 ["sqlite3_result_error_toobig", undefined, "*"], 689 ["sqlite3_result_int",undefined, "*", "int"], 690 ["sqlite3_result_null",undefined, "*"], 691 ["sqlite3_result_text",undefined, "*", "string", "int", "*"], 692 ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"], 693 ["sqlite3_shutdown", undefined], 694 ["sqlite3_sourceid", "string"], 695 ["sqlite3_sql", "string", "sqlite3_stmt*"], 696 ["sqlite3_step", "int", "sqlite3_stmt*"], 697 ["sqlite3_strglob", "int", "string","string"], 698 ["sqlite3_strlike", "int", "string","string","int"], 699 ["sqlite3_total_changes", "int", "sqlite3*"], 700 ["sqlite3_uri_boolean", "int", "string", "string", "int"], 701 ["sqlite3_uri_key", "string", "string", "int"], 702 ["sqlite3_uri_parameter", "string", "string", "string"], 703 ["sqlite3_value_blob", "*", "*"], 704 ["sqlite3_value_bytes","int", "*"], 705 ["sqlite3_value_double","f64", "*"], 706 ["sqlite3_value_text", "string", "*"], 707 ["sqlite3_value_type", "int", "*"], 708 ["sqlite3_vfs_find", "*", "string"], 709 ["sqlite3_vfs_register", "int", "*", "int"] 710 ]/*capi.wasm.bindingSignatures*/; 711 712 if(false && capi.wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){ 713 /* ^^^ "the problem" is that this is an option feature and the 714 build-time function-export list does not currently take 715 optional features into account. */ 716 capi.wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]); 717 } 718 719 /** 720 Functions which require BigInt (int64) support are separated from 721 the others because we need to conditionally bind them or apply 722 dummy impls, depending on the capabilities of the environment. 723 */ 724 capi.wasm.bindingSignatures.int64 = [ 725 ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]], 726 ["sqlite3_changes64","i64", ["sqlite3*"]], 727 ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]], 728 ["sqlite3_malloc64", "*","i64"], 729 ["sqlite3_msize", "i64", "*"], 730 ["sqlite3_realloc64", "*","*", "i64"], 731 ["sqlite3_total_changes64", "i64", ["sqlite3*"]], 732 ["sqlite3_uri_int64", "i64", ["string", "string", "i64"]] 733 ]; 734 735 /** 736 Functions which are intended solely for API-internal use by the 737 WASM components, not client code. These get installed into 738 capi.wasm. 739 740 TODO: get rid of sqlite3_wasm_vfs_unlink(). It is ill-conceived 741 and only rarely actually useful. 742 */ 743 capi.wasm.bindingSignatures.wasm = [ 744 ["sqlite3_wasm_vfs_unlink", "int", "string"] 745 ]; 746 747 748 /** 749 sqlite3.capi.wasm.pstack (pseudo-stack) holds a special-case 750 stack-style allocator intended only for use with _small_ data of 751 not more than (in total) a few kb in size, managed as if it were 752 stack-based. 753 754 It has only a single intended usage: 755 756 ``` 757 const stackPos = pstack.pointer; 758 try{ 759 const ptr = pstack.alloc(8); 760 // ==> pstack.pointer === ptr 761 const otherPtr = pstack.alloc(8); 762 // ==> pstack.pointer === otherPtr 763 ... 764 }finally{ 765 pstack.restore(stackPos); 766 // ==> pstack.pointer === stackPos 767 } 768 ``` 769 770 This allocator is much faster than a general-purpose one but is 771 limited to usage patterns like the one shown above. 772 773 It operates from a static range of memory which lives outside of 774 space managed by Emscripten's stack-management, so does not 775 collide with Emscripten-provided stack allocation APIs. The 776 memory lives in the WASM heap and can be used with routines such 777 as wasm.setMemValue() and any wasm.heap8u().slice(). 778 */ 779 capi.wasm.pstack = Object.assign(Object.create(null),{ 780 /** 781 Sets the current ppstack position to the given pointer. 782 Results are undefined if the passed-in value did not come from 783 this.pointer. 784 */ 785 restore: capi.wasm.exports.sqlite3_wasm_pstack_restore, 786 /** 787 Attempts to allocate the given number of bytes from the 788 pstack. On success, it zeroes out a block of memory of the 789 given size, adjusts the pstack pointer, and returns a pointer 790 to the memory. On error, returns throws a WasmAllocError. The 791 memory must eventually be released using restore(). 792 793 This method always adjusts the given value to be a multiple 794 of 8 bytes because failing to do so can lead to incorrect 795 results when reading and writing 64-bit values from/to the WASM 796 heap. 797 */ 798 alloc: (n)=>{ 799 return capi.wasm.exports.sqlite3_wasm_pstack_alloc(n) 800 || WasmAllocError.toss("Could not allocate",n, 801 "bytes from the pstack."); 802 } 803 // More methods get added after the capi.wasm object is populated 804 // by WhWasmUtilInstaller. 805 }); 806 /** 807 sqlite3.capi.wasm.pstack.pointer resolves to the current pstack 808 position pointer. This value is intended _only_ to be passed to restore(). 809 */ 810 Object.defineProperty(capi.wasm.pstack, 'pointer', { 811 configurable: false, iterable: true, writeable: false, 812 get: capi.wasm.exports.sqlite3_wasm_pstack_ptr 813 //Whether or not a setter as an alternative to restore() is 814 //clearer or would just lead to confusion is unclear. 815 //set: capi.wasm.exports.sqlite3_wasm_pstack_restore 816 }); 817 /** 818 sqlite3.capi.wasm.pstack.remaining resolves to the amount of 819 space remaining in the pstack. 820 */ 821 Object.defineProperty(capi.wasm.pstack, 'remaining', { 822 configurable: false, iterable: true, writeable: false, 823 get: capi.wasm.exports.sqlite3_wasm_pstack_remaining 824 }); 825 826 /** 827 An Error subclass specifically for reporting DB-level errors and 828 enabling clients to unambiguously identify such exceptions. 829 The C-level APIs never throw, but some of the higher-level 830 C-style APIs do and the object-oriented APIs use exceptions 831 exclusively to report errors. 832 */ 833 class SQLite3Error extends Error { 834 /** 835 Constructs this object with a message equal to all arguments 836 concatenated with a space between each one. 837 */ 838 constructor(...args){ 839 super(args.join(' ')); 840 this.name = 'SQLite3Error'; 841 } 842 }; 843 SQLite3Error.toss = (...args)=>{ 844 throw new SQLite3Error(args.join(' ')); 845 }; 846 847 /** State for sqlite3_wasmfs_opfs_dir(). */ 848 let __persistentDir = undefined; 849 /** 850 If the wasm environment has a WASMFS/OPFS-backed persistent 851 storage directory, its path is returned by this function. If it 852 does not then it returns "" (noting that "" is a falsy value). 853 854 The first time this is called, this function inspects the current 855 environment to determine whether persistence support is available 856 and, if it is, enables it (if needed). 857 858 This function currently only recognizes the WASMFS/OPFS storage 859 combination and its path refers to storage rooted in the 860 Emscripten-managed virtual filesystem. 861 */ 862 capi.sqlite3_wasmfs_opfs_dir = function(){ 863 if(undefined !== __persistentDir) return __persistentDir; 864 // If we have no OPFS, there is no persistent dir 865 const pdir = config.wasmfsOpfsDir; 866 if(!pdir 867 || !self.FileSystemHandle 868 || !self.FileSystemDirectoryHandle 869 || !self.FileSystemFileHandle){ 870 return __persistentDir = ""; 871 } 872 try{ 873 if(pdir && 0===capi.wasm.xCallWrapped( 874 'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir 875 )){ 876 return __persistentDir = pdir; 877 }else{ 878 return __persistentDir = ""; 879 } 880 }catch(e){ 881 // sqlite3_wasm_init_wasmfs() is not available 882 return __persistentDir = ""; 883 } 884 }; 885 886 /** 887 Experimental and subject to change or removal. 888 889 Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a 890 non-empty string and the given name starts with (that string + 891 '/'), else returns false. 892 893 Potential (but arguable) TODO: return true if the name is one of 894 (":localStorage:", "local", ":sessionStorage:", "session") and 895 kvvfs is available. 896 */ 897 capi.sqlite3_web_filename_is_persistent = function(name){ 898 const p = capi.sqlite3_wasmfs_opfs_dir(); 899 return (p && name) ? name.startsWith(p+'/') : false; 900 }; 901 902 // This bit is highly arguable and is incompatible with the fiddle shell. 903 if(false && 0===capi.wasm.exports.sqlite3_vfs_find(0)){ 904 /* Assume that sqlite3_initialize() has not yet been called. 905 This will be the case in an SQLITE_OS_KV build. */ 906 capi.wasm.exports.sqlite3_initialize(); 907 } 908 909 /** 910 Given an `sqlite3*`, an sqlite3_vfs name, and an optional db 911 name, returns a truthy value (see below) if that db handle uses 912 that VFS, else returns false. If pDb is falsy then the 3rd 913 argument is ignored and this function returns a truthy value if 914 the default VFS name matches that of the 2nd argument. Results 915 are undefined if pDb is truthy but refers to an invalid 916 pointer. The 3rd argument specifies the database name of the 917 given database connection to check, defaulting to the main db. 918 919 The 2nd and 3rd arguments may either be a JS string or a C-string 920 allocated from the wasm environment. 921 922 The truthy value it returns is a pointer to the `sqlite3_vfs` 923 object. 924 925 To permit safe use of this function from APIs which may be called 926 via the C stack (like SQL UDFs), this function does not throw: if 927 bad arguments cause a conversion error when passing into 928 wasm-space, false is returned. 929 */ 930 capi.sqlite3_web_db_uses_vfs = function(pDb,vfsName,dbName="main"){ 931 try{ 932 const pK = capi.sqlite3_vfs_find(vfsName); 933 if(!pK) return false; 934 else if(!pDb){ 935 return capi.sqlite3_vfs_find(0)===pK ? pK : false; 936 } 937 const ppVfs = capi.wasm.allocPtr(); 938 try{ 939 return ( 940 (0===capi.sqlite3_file_control( 941 pDb, dbName, capi.SQLITE_FCNTL_VFS_POINTER, ppVfs 942 )) && (capi.wasm.getPtrValue(ppVfs) === pK) 943 ) ? pK : false; 944 }finally{ 945 capi.wasm.dealloc(ppVfs); 946 } 947 }catch(e){ 948 /* Ignore - probably bad args to a wasm-bound function. */ 949 return false; 950 } 951 }; 952 953 /** 954 Returns an array of the names of all currently-registered sqlite3 955 VFSes. 956 */ 957 capi.sqlite3_web_vfs_list = function(){ 958 const rc = []; 959 let pVfs = capi.sqlite3_vfs_find(0); 960 while(pVfs){ 961 const oVfs = new capi.sqlite3_vfs(pVfs); 962 rc.push(capi.wasm.cstringToJs(oVfs.$zName)); 963 pVfs = oVfs.$pNext; 964 oVfs.dispose(); 965 } 966 return rc; 967 }; 968 969 /** 970 Serializes the given `sqlite3*` pointer to a Uint8Array, as per 971 sqlite3_serialize(). On success it returns a Uint8Array. On 972 error it throws with a description of the problem. 973 */ 974 capi.sqlite3_web_db_export = function(pDb){ 975 if(!pDb) toss('Invalid sqlite3* argument.'); 976 const wasm = capi.wasm; 977 if(!wasm.bigIntEnabled) toss('BigInt64 support is not enabled.'); 978 const stack = wasm.pstack.pointer; 979 let pOut; 980 try{ 981 const pSize = wasm.pstack.alloc(8/*i64*/ + wasm.ptrSizeof); 982 const ppOut = pSize + 8; 983 /** 984 Maintenance reminder, since this cost a full hour of grief 985 and confusion: if the order of pSize/ppOut are reversed in 986 that memory block, fetching the value of pSize after the 987 export reads a garbage size because it's not on an 8-byte 988 memory boundary! 989 */ 990 let rc = wasm.exports.sqlite3_wasm_db_serialize( 991 pDb, ppOut, pSize, 0 992 ); 993 if(rc){ 994 toss("Database serialization failed with code", 995 sqlite3.capi.sqlite3_web_rc_str(rc)); 996 } 997 pOut = wasm.getPtrValue(ppOut); 998 const nOut = wasm.getMemValue(pSize, 'i64'); 999 rc = nOut 1000 ? wasm.heap8u().slice(pOut, pOut + Number(nOut)) 1001 : new Uint8Array(); 1002 return rc; 1003 }catch(e){ 1004 console.error('internal error?',e); 1005 throw w; 1006 }finally{ 1007 if(pOut) wasm.exports.sqlite3_free(pOut); 1008 wasm.pstack.restore(stack); 1009 } 1010 }; 1011 1012 if( capi.util.isMainWindow() ){ 1013 /* Features specific to the main window thread... */ 1014 1015 /** 1016 Internal helper for sqlite3_web_kvvfs_clear() and friends. 1017 Its argument should be one of ('local','session',''). 1018 */ 1019 const __kvvfsInfo = function(which){ 1020 const rc = Object.create(null); 1021 rc.prefix = 'kvvfs-'+which; 1022 rc.stores = []; 1023 if('session'===which || ''===which) rc.stores.push(self.sessionStorage); 1024 if('local'===which || ''===which) rc.stores.push(self.localStorage); 1025 return rc; 1026 }; 1027 1028 /** 1029 Clears all storage used by the kvvfs DB backend, deleting any 1030 DB(s) stored there. Its argument must be either 'session', 1031 'local', or ''. In the first two cases, only sessionStorage 1032 resp. localStorage is cleared. If it's an empty string (the 1033 default) then both are cleared. Only storage keys which match 1034 the pattern used by kvvfs are cleared: any other client-side 1035 data are retained. 1036 1037 This function is only available in the main window thread. 1038 1039 Returns the number of entries cleared. 1040 */ 1041 capi.sqlite3_web_kvvfs_clear = function(which=''){ 1042 let rc = 0; 1043 const kvinfo = __kvvfsInfo(which); 1044 kvinfo.stores.forEach((s)=>{ 1045 const toRm = [] /* keys to remove */; 1046 let i; 1047 for( i = 0; i < s.length; ++i ){ 1048 const k = s.key(i); 1049 if(k.startsWith(kvinfo.prefix)) toRm.push(k); 1050 } 1051 toRm.forEach((kk)=>s.removeItem(kk)); 1052 rc += toRm.length; 1053 }); 1054 return rc; 1055 }; 1056 1057 /** 1058 This routine guesses the approximate amount of 1059 window.localStorage and/or window.sessionStorage in use by the 1060 kvvfs database backend. Its argument must be one of 1061 ('session', 'local', ''). In the first two cases, only 1062 sessionStorage resp. localStorage is counted. If it's an empty 1063 string (the default) then both are counted. Only storage keys 1064 which match the pattern used by kvvfs are counted. The returned 1065 value is the "length" value of every matching key and value, 1066 noting that JavaScript stores each character in 2 bytes. 1067 1068 Note that the returned size is not authoritative from the 1069 perspective of how much data can fit into localStorage and 1070 sessionStorage, as the precise algorithms for determining 1071 those limits are unspecified and may include per-entry 1072 overhead invisible to clients. 1073 */ 1074 capi.sqlite3_web_kvvfs_size = function(which=''){ 1075 let sz = 0; 1076 const kvinfo = __kvvfsInfo(which); 1077 kvinfo.stores.forEach((s)=>{ 1078 let i; 1079 for(i = 0; i < s.length; ++i){ 1080 const k = s.key(i); 1081 if(k.startsWith(kvinfo.prefix)){ 1082 sz += k.length; 1083 sz += s.getItem(k).length; 1084 } 1085 } 1086 }); 1087 return sz * 2 /* because JS uses 2-byte char encoding */; 1088 }; 1089 1090 }/* main-window-only bits */ 1091 1092 1093 /* The remainder of the API will be set up in later steps. */ 1094 const sqlite3 = { 1095 WasmAllocError: WasmAllocError, 1096 SQLite3Error: SQLite3Error, 1097 capi, 1098 config, 1099 /** 1100 Performs any optional asynchronous library-level initialization 1101 which might be required. This function returns a Promise which 1102 resolves to the sqlite3 namespace object. It _ignores any 1103 errors_ in the asynchronous init process, as such components 1104 are all optional. If called more than once, the second and 1105 subsequent calls are no-ops which return a pre-resolved 1106 Promise. 1107 1108 Ideally this function is called as part of the Promise chain 1109 which handles the loading and bootstrapping of the API. If not 1110 then it must be called by client-level code, which must not use 1111 the library until the returned promise resolves. 1112 1113 Bug: if called while a prior call is still resolving, the 2nd 1114 call will resolve prematurely, before the 1st call has finished 1115 resolving. The current build setup precludes that possibility, 1116 so it's only a hypothetical problem if/when this function 1117 ever needs to be invoked by clients. 1118 1119 In Emscripten-based builds, this function is called 1120 automatically and deleted from this object. 1121 */ 1122 asyncPostInit: async function(){ 1123 let lip = sqlite3ApiBootstrap.initializersAsync; 1124 delete sqlite3ApiBootstrap.initializersAsync; 1125 if(!lip || !lip.length) return Promise.resolve(sqlite3); 1126 // Is it okay to resolve these in parallel or do we need them 1127 // to resolve in order? We currently only have 1, so it 1128 // makes no difference. 1129 lip = lip.map((f)=>f(sqlite3).catch(()=>{})); 1130 //let p = lip.shift(); 1131 //while(lip.length) p = p.then(lip.shift()); 1132 //return p.then(()=>sqlite3); 1133 return Promise.all(lip).then(()=>sqlite3); 1134 } 1135 }; 1136 sqlite3ApiBootstrap.initializers.forEach((f)=>f(sqlite3)); 1137 delete sqlite3ApiBootstrap.initializers; 1138 sqlite3ApiBootstrap.sqlite3 = sqlite3; 1139 return sqlite3; 1140}/*sqlite3ApiBootstrap()*/; 1141/** 1142 self.sqlite3ApiBootstrap.initializers is an internal detail used by 1143 the various pieces of the sqlite3 API's amalgamation process. It 1144 must not be modified by client code except when plugging such code 1145 into the amalgamation process. 1146 1147 Each component of the amalgamation is expected to append a function 1148 to this array. When sqlite3ApiBootstrap() is called for the first 1149 time, each such function will be called (in their appended order) 1150 and passed the sqlite3 namespace object, into which they can install 1151 their features (noting that most will also require that certain 1152 features alread have been installed). At the end of that process, 1153 this array is deleted. 1154 1155 Note that the order of insertion into this array is significant for 1156 some pieces. e.g. sqlite3.capi.wasm cannot be fully utilized until 1157 the whwasmutil.js part is plugged in. 1158*/ 1159self.sqlite3ApiBootstrap.initializers = []; 1160/** 1161 self.sqlite3ApiBootstrap.initializersAsync is an internal detail 1162 used by the sqlite3 API's amalgamation process. It must not be 1163 modified by client code except when plugging such code into the 1164 amalgamation process. 1165 1166 Counterpart of self.sqlite3ApiBootstrap.initializers, specifically 1167 for initializers which are asynchronous. All functions in this list 1168 take the sqlite3 object as their argument and MUST return a 1169 Promise. Both the resolved value and rejection cases are ignored. 1170 1171 This list is not processed until the client calls 1172 sqlite3.asyncPostInit(). This means, for example, that intializers 1173 added to self.sqlite3ApiBootstrap.initializers may push entries to 1174 this list. 1175*/ 1176self.sqlite3ApiBootstrap.initializersAsync = []; 1177/** 1178 Client code may assign sqlite3ApiBootstrap.defaultConfig an 1179 object-type value before calling sqlite3ApiBootstrap() (without 1180 arguments) in order to tell that call to use this object as its 1181 default config value. The intention of this is to provide 1182 downstream clients with a reasonably flexible approach for plugging in 1183 an environment-suitable configuration without having to define a new 1184 global-scope symbol. 1185*/ 1186self.sqlite3ApiBootstrap.defaultConfig = Object.create(null); 1187/** 1188 Placeholder: gets installed by the first call to 1189 self.sqlite3ApiBootstrap(). However, it is recommended that the 1190 caller of sqlite3ApiBootstrap() capture its return value and delete 1191 self.sqlite3ApiBootstrap after calling it. It returns the same 1192 value which will be stored here. 1193*/ 1194self.sqlite3ApiBootstrap.sqlite3 = undefined; 1195