1/* 2 2022-07-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 glues together disparate pieces of JS which are loaded in 14 previous steps of the sqlite3-api.js bootstrapping process: 15 sqlite3-api-prologue.js, whwasmutil.js, and jaccwabyt.js. It 16 initializes the main API pieces so that the downstream components 17 (e.g. sqlite3-api-oo1.js) have all that they need. 18*/ 19self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 20 'use strict'; 21 const toss = (...args)=>{throw new Error(args.join(' '))}; 22 const toss3 = sqlite3.SQLite3Error.toss; 23 const capi = sqlite3.capi, wasm = capi.wasm, util = capi.util; 24 self.WhWasmUtilInstaller(capi.wasm); 25 delete self.WhWasmUtilInstaller; 26 27 if(0){ 28 /* "The problem" is that the following isn't type-safe. 29 OTOH, nothing about WASM pointers is. */ 30 /** 31 Add the `.pointer` xWrap() signature entry to extend the 32 `pointer` arg handler to check for a `pointer` property. This 33 can be used to permit, e.g., passing an sqlite3.oo1.DB instance 34 to a C-style sqlite3_xxx function which takes an `sqlite3*` 35 argument. 36 */ 37 const xPointer = wasm.xWrap.argAdapter('pointer'); 38 const adapter = function(v){ 39 if(v && v.constructor){ 40 const x = v.pointer; 41 if(Number.isInteger(x)) return x; 42 else toss("Invalid (object) type for .pointer-type argument."); 43 } 44 return xPointer(v); 45 }; 46 wasm.xWrap.argAdapter('.pointer', adapter); 47 } /* ".pointer" xWrap() argument adapter */ 48 49 if(1){/* Convert Arrays and certain TypedArrays to strings for 50 'flexible-string'-type arguments */ 51 const xString = wasm.xWrap.argAdapter('string'); 52 wasm.xWrap.argAdapter( 53 'flexible-string', (v)=>xString(util.flexibleString(v)) 54 ); 55 } 56 57 if(1){// WhWasmUtil.xWrap() bindings... 58 /** 59 Add some descriptive xWrap() aliases for '*' intended to (A) 60 initially improve readability/correctness of capi.signatures 61 and (B) eventually perhaps provide automatic conversion from 62 higher-level representations, e.g. capi.sqlite3_vfs to 63 `sqlite3_vfs*` via capi.sqlite3_vfs.pointer. 64 */ 65 const aPtr = wasm.xWrap.argAdapter('*'); 66 wasm.xWrap.argAdapter('sqlite3*', aPtr) 67 ('sqlite3_stmt*', aPtr) 68 ('sqlite3_context*', aPtr) 69 ('sqlite3_value*', aPtr) 70 ('void*', aPtr); 71 wasm.xWrap.resultAdapter('sqlite3*', aPtr) 72 ('sqlite3_stmt*', aPtr) 73 ('sqlite3_context*', aPtr) 74 ('void*', aPtr); 75 76 /** 77 Populate api object with sqlite3_...() by binding the "raw" wasm 78 exports into type-converting proxies using wasm.xWrap(). 79 */ 80 for(const e of wasm.bindingSignatures){ 81 capi[e[0]] = wasm.xWrap.apply(null, e); 82 } 83 for(const e of wasm.bindingSignatures.wasm){ 84 capi.wasm[e[0]] = wasm.xWrap.apply(null, e); 85 } 86 87 /* For C API functions which cannot work properly unless 88 wasm.bigIntEnabled is true, install a bogus impl which 89 throws if called when bigIntEnabled is false. */ 90 const fI64Disabled = function(fname){ 91 return ()=>toss(fname+"() disabled due to lack", 92 "of BigInt support in this build."); 93 }; 94 for(const e of wasm.bindingSignatures.int64){ 95 capi[e[0]] = wasm.bigIntEnabled 96 ? wasm.xWrap.apply(null, e) 97 : fI64Disabled(e[0]); 98 } 99 100 if(wasm.exports.sqlite3_wasm_db_error){ 101 util.sqlite3_wasm_db_error = capi.wasm.xWrap( 102 'sqlite3_wasm_db_error', 'int', 'sqlite3*', 'int', 'string' 103 ); 104 }else{ 105 util.sqlite3_wasm_db_error = function(pDb,errCode,msg){ 106 console.warn("sqlite3_wasm_db_error() is not exported.",arguments); 107 return errCode; 108 }; 109 } 110 111 /** 112 When registering a VFS and its related components it may be 113 necessary to ensure that JS keeps a reference to them to keep 114 them from getting garbage collected. Simply pass each such value 115 to this function and a reference will be held to it for the life 116 of the app. 117 */ 118 capi.sqlite3_vfs_register.addReference = function f(...args){ 119 if(!f._) f._ = []; 120 f._.push(...args); 121 }; 122 123 }/*xWrap() bindings*/; 124 125 /** 126 Internal helper to assist in validating call argument counts in 127 the hand-written sqlite3_xyz() wrappers. We do this only for 128 consistency with non-special-case wrappings. 129 */ 130 const __dbArgcMismatch = (pDb,f,n)=>{ 131 return sqlite3.util.sqlite3_wasm_db_error(pDb, capi.SQLITE_MISUSE, 132 f+"() requires "+n+" argument"+ 133 (1===n?'':'s')+"."); 134 }; 135 136 /** 137 Helper for flexible-string conversions which require a 138 byte-length counterpart argument. Passed a value and its 139 ostensible length, this function returns [V,N], where V 140 is either v or a transformed copy of v and N is either n, 141 -1, or the byte length of v (if it's a byte array). 142 */ 143 const __flexiString = function(v,n){ 144 if('string'===typeof v){ 145 n = -1; 146 }else if(util.isSQLableTypedArray(v)){ 147 n = v.byteLength; 148 v = util.typedArrayToString(v); 149 }else if(Array.isArray(v)){ 150 v = v.join(''); 151 n = -1; 152 } 153 return [v, n]; 154 }; 155 156 if(1){/* Special-case handling of sqlite3_exec() */ 157 const __exec = wasm.xWrap("sqlite3_exec", "int", 158 ["sqlite3*", "flexible-string", "*", "*", "**"]); 159 /* Documented in the api object's initializer. */ 160 capi.sqlite3_exec = function f(pDb, sql, callback, pVoid, pErrMsg){ 161 if(f.length!==arguments.length){ 162 return __dbArgcMismatch(pDb,"sqlite3_exec",f.length); 163 }else if('function' !== typeof callback){ 164 return __exec(pDb, sql, callback, pVoid, pErrMsg); 165 } 166 /* Wrap the callback in a WASM-bound function and convert the callback's 167 `(char**)` arguments to arrays of strings... */ 168 const wasm = capi.wasm; 169 const cbwrap = function(pVoid, nCols, pColVals, pColNames){ 170 let rc = capi.SQLITE_ERROR; 171 try { 172 let aVals = [], aNames = [], i = 0, offset = 0; 173 for( ; i < nCols; offset += (wasm.ptrSizeof * ++i) ){ 174 aVals.push( wasm.cstringToJs(wasm.getPtrValue(pColVals + offset)) ); 175 aNames.push( wasm.cstringToJs(wasm.getPtrValue(pColNames + offset)) ); 176 } 177 rc = callback(pVoid, nCols, aVals, aNames) | 0; 178 /* The first 2 args of the callback are useless for JS but 179 we want the JS mapping of the C API to be as close to the 180 C API as possible. */ 181 }catch(e){ 182 /* If we set the db error state here, the higher-level exec() call 183 replaces it with its own, so we have no way of reporting the 184 exception message except the console. We must not propagate 185 exceptions through the C API. */ 186 } 187 return rc; 188 }; 189 let pFunc, rc; 190 try{ 191 pFunc = wasm.installFunction("ipipp", cbwrap); 192 rc = __exec(pDb, sql, pFunc, pVoid, pErrMsg); 193 }catch(e){ 194 rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR, 195 "Error running exec(): "+e.message); 196 }finally{ 197 if(pFunc) wasm.uninstallFunction(pFunc); 198 } 199 return rc; 200 }; 201 }/*sqlite3_exec() proxy*/; 202 203 if(1){/* Special-case handling of sqlite3_create_function_v2() 204 and sqlite3_create_window_function() */ 205 const sqlite3CreateFunction = wasm.xWrap( 206 "sqlite3_create_function_v2", "int", 207 ["sqlite3*", "string"/*funcName*/, "int"/*nArg*/, 208 "int"/*eTextRep*/, "*"/*pApp*/, 209 "*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/, "*"/*xDestroy*/] 210 ); 211 const sqlite3CreateWindowFunction = wasm.xWrap( 212 "sqlite3_create_window_function", "int", 213 ["sqlite3*", "string"/*funcName*/, "int"/*nArg*/, 214 "int"/*eTextRep*/, "*"/*pApp*/, 215 "*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/, 216 "*"/*xInverse*/, "*"/*xDestroy*/] 217 ); 218 219 const __udfSetResult = function(pCtx, val){ 220 //console.warn("udfSetResult",typeof val, val); 221 switch(typeof val) { 222 case 'boolean': 223 capi.sqlite3_result_int(pCtx, val ? 1 : 0); 224 break; 225 case 'bigint': 226 if(wasm.bigIntEnabled){ 227 if(util.bigIntFits64(val)) capi.sqlite3_result_int64(pCtx, val); 228 else toss3("BigInt value",val.toString(),"is too BigInt for int64."); 229 }else if(util.bigIntFits32(val)){ 230 capi.sqlite3_result_int(pCtx, Number(val)); 231 }else if(util.bigIntFitsDouble(val)){ 232 capi.sqlite3_result_double(pCtx, Number(val)); 233 }else{ 234 toss3("BigInt value",val.toString(),"is too BigInt."); 235 } 236 break; 237 case 'number': { 238 (util.isInt32(val) 239 ? capi.sqlite3_result_int 240 : capi.sqlite3_result_double)(pCtx, val); 241 break; 242 } 243 case 'string': 244 capi.sqlite3_result_text(pCtx, val, -1, capi.SQLITE_TRANSIENT); 245 break; 246 case 'object': 247 if(null===val/*yes, typeof null === 'object'*/) { 248 capi.sqlite3_result_null(pCtx); 249 break; 250 }else if(util.isBindableTypedArray(val)){ 251 const pBlob = wasm.allocFromTypedArray(val); 252 capi.sqlite3_result_blob( 253 pCtx, pBlob, val.byteLength, 254 wasm.exports[sqlite3.config.deallocExportName] 255 ); 256 break; 257 } 258 // else fall through 259 default: 260 toss3("Don't not how to handle this UDF result value:",(typeof val), val); 261 }; 262 }/*__udfSetResult()*/; 263 264 const __udfConvertArgs = function(argc, pArgv){ 265 let i, pVal, valType, arg; 266 const tgt = []; 267 for(i = 0; i < argc; ++i){ 268 pVal = wasm.getPtrValue(pArgv + (wasm.ptrSizeof * i)); 269 /** 270 Curiously: despite ostensibly requiring 8-byte 271 alignment, the pArgv array is parcelled into chunks of 272 4 bytes (1 pointer each). The values those point to 273 have 8-byte alignment but the individual argv entries 274 do not. 275 */ 276 valType = capi.sqlite3_value_type(pVal); 277 switch(valType){ 278 case capi.SQLITE_INTEGER: 279 if(wasm.bigIntEnabled){ 280 arg = capi.sqlite3_value_int64(pVal); 281 if(util.bigIntFitsDouble(arg)) arg = Number(arg); 282 } 283 else arg = capi.sqlite3_value_double(pVal)/*yes, double, for larger integers*/; 284 break; 285 case capi.SQLITE_FLOAT: 286 arg = capi.sqlite3_value_double(pVal); 287 break; 288 case capi.SQLITE_TEXT: 289 arg = capi.sqlite3_value_text(pVal); 290 break; 291 case capi.SQLITE_BLOB:{ 292 const n = capi.sqlite3_value_bytes(pVal); 293 const pBlob = capi.sqlite3_value_blob(pVal); 294 if(n && !pBlob) sqlite3.WasmAllocError.toss( 295 "Cannot allocate memory for blob argument of",n,"byte(s)" 296 ); 297 arg = n ? wasm.heap8u().slice(pBlob, pBlob + Number(n)) : null; 298 break; 299 } 300 case capi.SQLITE_NULL: 301 arg = null; break; 302 default: 303 toss3("Unhandled sqlite3_value_type()",valType, 304 "is possibly indicative of incorrect", 305 "pointer size assumption."); 306 } 307 tgt.push(arg); 308 } 309 return tgt; 310 }/*__udfConvertArgs()*/; 311 312 const __udfSetError = (pCtx, e)=>{ 313 if(e instanceof sqlite3.WasmAllocError){ 314 capi.sqlite3_result_error_nomem(pCtx); 315 }else{ 316 capi.sqlite3_result_error(pCtx, e.message, -1); 317 } 318 }; 319 320 const __xFunc = function(callback){ 321 return function(pCtx, argc, pArgv){ 322 try{ __udfSetResult(pCtx, callback(pCtx, ...__udfConvertArgs(argc, pArgv))) } 323 catch(e){ 324 //console.error('xFunc() caught:',e); 325 __udfSetError(pCtx, e); 326 } 327 }; 328 }; 329 330 const __xInverseAndStep = function(callback){ 331 return function(pCtx, argc, pArgv){ 332 try{ callback(pCtx, ...__udfConvertArgs(argc, pArgv)) } 333 catch(e){ __udfSetError(pCtx, e) } 334 }; 335 }; 336 337 const __xFinalAndValue = function(callback){ 338 return function(pCtx){ 339 try{ __udfSetResult(pCtx, callback(pCtx)) } 340 catch(e){ __udfSetError(pCtx, e) } 341 }; 342 }; 343 344 const __xDestroy = function(callback){ 345 return function(pVoid){ 346 try{ callback(pVoid) } 347 catch(e){ console.error("UDF xDestroy method threw:",e) } 348 }; 349 }; 350 351 const __xMap = Object.assign(Object.create(null), { 352 xFunc: {sig:'v(pip)', f:__xFunc}, 353 xStep: {sig:'v(pip)', f:__xInverseAndStep}, 354 xInverse: {sig:'v(pip)', f:__xInverseAndStep}, 355 xFinal: {sig:'v(p)', f:__xFinalAndValue}, 356 xValue: {sig:'v(p)', f:__xFinalAndValue}, 357 xDestroy: {sig:'v(p)', f:__xDestroy} 358 }); 359 360 const __xWrapFuncs = function(theFuncs, tgtUninst){ 361 const rc = [] 362 let k; 363 for(k in theFuncs){ 364 let fArg = theFuncs[k]; 365 if('function'===typeof fArg){ 366 const w = __xMap[k]; 367 fArg = wasm.installFunction(w.sig, w.f(fArg)); 368 tgtUninst.push(fArg); 369 } 370 rc.push(fArg); 371 } 372 return rc; 373 }; 374 375 /* Documented in the api object's initializer. */ 376 capi.sqlite3_create_function_v2 = function f( 377 pDb, funcName, nArg, eTextRep, pApp, 378 xFunc, //void (*xFunc)(sqlite3_context*,int,sqlite3_value**) 379 xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**) 380 xFinal, //void (*xFinal)(sqlite3_context*) 381 xDestroy //void (*xDestroy)(void*) 382 ){ 383 if(f.length!==arguments.length){ 384 return __dbArgcMismatch(pDb,"sqlite3_create_function_v2",f.length); 385 } 386 /* Wrap the callbacks in a WASM-bound functions... */ 387 const wasm = capi.wasm; 388 const uninstall = [/*funcs to uninstall on error*/]; 389 let rc; 390 try{ 391 const funcArgs = __xWrapFuncs({xFunc, xStep, xFinal, xDestroy}, 392 uninstall); 393 rc = sqlite3CreateFunction(pDb, funcName, nArg, eTextRep, 394 pApp, ...funcArgs); 395 }catch(e){ 396 console.error("sqlite3_create_function_v2() setup threw:",e); 397 for(let v of uninstall){ 398 wasm.uninstallFunction(v); 399 } 400 rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR, 401 "Creation of UDF threw: "+e.message); 402 } 403 return rc; 404 }; 405 406 capi.sqlite3_create_function = function f( 407 pDb, funcName, nArg, eTextRep, pApp, 408 xFunc, xStep, xFinal 409 ){ 410 return (f.length===arguments.length) 411 ? capi.sqlite3_create_function_v2(pDb, funcName, nArg, eTextRep, 412 pApp, xFunc, xStep, xFinal, 0) 413 : __dbArgcMismatch(pDb,"sqlite3_create_function",f.length); 414 }; 415 416 /* Documented in the api object's initializer. */ 417 capi.sqlite3_create_window_function = function f( 418 pDb, funcName, nArg, eTextRep, pApp, 419 xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**) 420 xFinal, //void (*xFinal)(sqlite3_context*) 421 xValue, //void (*xFinal)(sqlite3_context*) 422 xInverse,//void (*xStep)(sqlite3_context*,int,sqlite3_value**) 423 xDestroy //void (*xDestroy)(void*) 424 ){ 425 if(f.length!==arguments.length){ 426 return __dbArgcMismatch(pDb,"sqlite3_create_window_function",f.length); 427 } 428 /* Wrap the callbacks in a WASM-bound functions... */ 429 const wasm = capi.wasm; 430 const uninstall = [/*funcs to uninstall on error*/]; 431 let rc; 432 try{ 433 const funcArgs = __xWrapFuncs({xStep, xFinal, xValue, xInverse, xDestroy}, 434 uninstall); 435 rc = sqlite3CreateFunction(pDb, funcName, nArg, eTextRep, 436 pApp, ...funcArgs); 437 }catch(e){ 438 console.error("sqlite3_create_function_v2() setup threw:",e); 439 for(let v of uninstall){ 440 wasm.uninstallFunction(v); 441 } 442 rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR, 443 "Creation of UDF threw: "+e.message); 444 } 445 return rc; 446 }; 447 /** 448 A helper for UDFs implemented in JS and bound to WASM by the 449 client. Given a JS value, udfSetResult(pCtx,X) calls one of the 450 sqlite3_result_xyz(pCtx,...) routines, depending on X's data 451 type: 452 453 - `null`: sqlite3_result_null() 454 - `boolean`: sqlite3_result_int() 455 - `number': sqlite3_result_int() or sqlite3_result_double() 456 - `string`: sqlite3_result_text() 457 - Uint8Array or Int8Array: sqlite3_result_blob() 458 459 Anything else triggers sqlite3_result_error(). 460 */ 461 capi.sqlite3_create_function_v2.udfSetResult = 462 capi.sqlite3_create_function.udfSetResult = 463 capi.sqlite3_create_window_function.udfSetResult = __udfSetResult; 464 465 /** 466 A helper for UDFs implemented in JS and bound to WASM by the 467 client. When passed the 468 (argc,argv) values from the UDF-related functions which receive 469 them (xFunc, xStep, xInverse), it creates a JS array 470 representing those arguments, converting each to JS in a manner 471 appropriate to its data type: numeric, text, blob 472 (Uint8Array()), or null. 473 474 Results are undefined if it's passed anything other than those 475 two arguments from those specific contexts. 476 477 Thus an argc of 4 will result in a length-4 array containing 478 the converted values from the corresponding argv. 479 480 The conversion will throw only on allocation error or an internal 481 error. 482 */ 483 capi.sqlite3_create_function_v2.udfConvertArgs = 484 capi.sqlite3_create_function.udfConvertArgs = 485 capi.sqlite3_create_window_function.udfConvertArgs = __udfConvertArgs; 486 487 /** 488 A helper for UDFs implemented in JS and bound to WASM by the 489 client. It expects to be a passed `(sqlite3_context*, Error)` 490 (i.e. an exception object). And it sets the current UDF's 491 result to sqlite3_result_error_nomem() or sqlite3_result_error(), 492 depending on whether the 2nd argument is a 493 sqlite3.WasmAllocError object or not. 494 */ 495 capi.sqlite3_create_function_v2.udfSetError = 496 capi.sqlite3_create_function.udfSetError = 497 capi.sqlite3_create_window_function.udfSetError = __udfSetError; 498 499 }/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/; 500 501 if(1){/* Special-case handling of sqlite3_prepare_v2() and 502 sqlite3_prepare_v3() */ 503 /** 504 Scope-local holder of the two impls of sqlite3_prepare_v2/v3(). 505 */ 506 const __prepare = Object.create(null); 507 /** 508 This binding expects a JS string as its 2nd argument and 509 null as its final argument. In order to compile multiple 510 statements from a single string, the "full" impl (see 511 below) must be used. 512 */ 513 __prepare.basic = wasm.xWrap('sqlite3_prepare_v3', 514 "int", ["sqlite3*", "string", 515 "int"/*ignored for this impl!*/, 516 "int", "**", 517 "**"/*MUST be 0 or null or undefined!*/]); 518 /** 519 Impl which requires that the 2nd argument be a pointer 520 to the SQL string, instead of being converted to a 521 string. This variant is necessary for cases where we 522 require a non-NULL value for the final argument 523 (exec()'ing multiple statements from one input 524 string). For simpler cases, where only the first 525 statement in the SQL string is required, the wrapper 526 named sqlite3_prepare_v2() is sufficient and easier to 527 use because it doesn't require dealing with pointers. 528 */ 529 __prepare.full = wasm.xWrap('sqlite3_prepare_v3', 530 "int", ["sqlite3*", "*", "int", "int", 531 "**", "**"]); 532 533 /* Documented in the api object's initializer. */ 534 capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){ 535 if(f.length!==arguments.length){ 536 return __dbArgcMismatch(pDb,"sqlite3_prepare_v3",f.length); 537 } 538 const [xSql, xSqlLen] = __flexiString(sql, sqlLen); 539 switch(typeof xSql){ 540 case 'string': return __prepare.basic(pDb, xSql, xSqlLen, prepFlags, ppStmt, null); 541 case 'number': return __prepare.full(pDb, xSql, xSqlLen, prepFlags, ppStmt, pzTail); 542 default: 543 return util.sqlite3_wasm_db_error( 544 pDb, capi.SQLITE_MISUSE, 545 "Invalid SQL argument type for sqlite3_prepare_v2/v3()." 546 ); 547 } 548 }; 549 550 /* Documented in the api object's initializer. */ 551 capi.sqlite3_prepare_v2 = function f(pDb, sql, sqlLen, ppStmt, pzTail){ 552 return (f.length===arguments.length) 553 ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail) 554 : __dbArgcMismatch(pDb,"sqlite3_prepare_v2",f.length); 555 }; 556 }/*sqlite3_prepare_v2/v3()*/; 557 558 if(1){// Extend wasm.pstack, now that the wasm utils are installed 559 /** 560 Allocates n chunks, each sz bytes, as a single memory block and 561 returns the addresses as an array of n element, each holding 562 the address of one chunk. 563 564 Throws a WasmAllocError if allocation fails. 565 566 Example: 567 568 ``` 569 const [p1, p2, p3] = wasm.pstack.allocChunks(3,4); 570 ``` 571 */ 572 wasm.pstack.allocChunks = (n,sz)=>{ 573 const mem = wasm.pstack.alloc(n * sz); 574 const rc = []; 575 let i = 0, offset = 0; 576 for(; i < n; offset = (sz * ++i)){ 577 rc.push(mem + offset); 578 } 579 return rc; 580 }; 581 582 /** 583 A convenience wrapper for allocChunks() which sizes each chunks 584 as either 8 bytes (safePtrSize is truthy) or wasm.ptrSizeof (if 585 safePtrSize is falsy). 586 587 How it returns its result differs depending on its first 588 argument: if it's 1, it returns a single pointer value. If it's 589 more than 1, it returns the same as allocChunks(). 590 591 When a returned pointers will refer to a 64-bit value, e.g. a 592 double or int64, and that value must be written or fetched, 593 e.g. using wasm.setMemValue() or wasm.getMemValue(), it is 594 important that the pointer in question be aligned to an 8-byte 595 boundary or else it will not be fetched or written properly and 596 will corrupt or read neighboring memory. 597 598 However, when all pointers involved point to "small" data, it 599 is safe to pass a falsy value to save to memory. 600 */ 601 wasm.pstack.allocPtr = (n=1,safePtrSize=true) =>{ 602 return 1===n 603 ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.ptrSizeof) 604 : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.ptrSizeof); 605 }; 606 }/*wasm.pstack filler*/ 607 608 /** 609 Install JS<->C struct bindings for the non-opaque struct types we 610 need... */ 611 sqlite3.StructBinder = self.Jaccwabyt({ 612 heap: 0 ? wasm.memory : wasm.heap8u, 613 alloc: wasm.alloc, 614 dealloc: wasm.dealloc, 615 functionTable: wasm.functionTable, 616 bigIntEnabled: wasm.bigIntEnabled, 617 memberPrefix: '$' 618 }); 619 delete self.Jaccwabyt; 620 621 {/* Import C-level constants and structs... */ 622 const cJson = wasm.xCall('sqlite3_wasm_enum_json'); 623 if(!cJson){ 624 toss("Maintenance required: increase sqlite3_wasm_enum_json()'s", 625 "static buffer size!"); 626 } 627 wasm.ctype = JSON.parse(wasm.cstringToJs(cJson)); 628 //console.debug('wasm.ctype length =',wasm.cstrlen(cJson)); 629 for(const t of ['access', 'blobFinalizers', 'dataTypes', 630 'encodings', 'fcntl', 'flock', 'ioCap', 631 'openFlags', 'prepareFlags', 'resultCodes', 632 'serialize', 'syncFlags', 'udfFlags', 633 'version' 634 ]){ 635 for(const e of Object.entries(wasm.ctype[t])){ 636 // ^^^ [k,v] there triggers a buggy code transormation via one 637 // of the Emscripten-driven optimizers. 638 capi[e[0]] = e[1]; 639 } 640 } 641 const __rcMap = Object.create(null); 642 for(const t of ['resultCodes']){ 643 for(const e of Object.entries(wasm.ctype[t])){ 644 __rcMap[e[1]] = e[0]; 645 } 646 } 647 /** 648 For the given integer, returns the SQLITE_xxx result code as a 649 string, or undefined if no such mapping is found. 650 */ 651 capi.sqlite3_web_rc_str = (rc)=>__rcMap[rc]; 652 /* Bind all registered C-side structs... */ 653 for(const s of wasm.ctype.structs){ 654 capi[s.name] = sqlite3.StructBinder(s); 655 } 656 }/*end C constant imports*/ 657 658 sqlite3.version = Object.assign(Object.create(null),{ 659 library: sqlite3.capi.sqlite3_libversion(), 660 sourceId: sqlite3.capi.sqlite3_sourceid() 661 }); 662}); 663 664