13961b263Sstephan/* 23961b263Sstephan 2022-07-22 33961b263Sstephan 43961b263Sstephan The author disclaims copyright to this source code. In place of a 53961b263Sstephan legal notice, here is a blessing: 63961b263Sstephan 73961b263Sstephan * May you do good and not evil. 83961b263Sstephan * May you find forgiveness for yourself and forgive others. 93961b263Sstephan * May you share freely, never taking more than you give. 103961b263Sstephan 113961b263Sstephan *********************************************************************** 123961b263Sstephan 133961b263Sstephan This file glues together disparate pieces of JS which are loaded in 143961b263Sstephan previous steps of the sqlite3-api.js bootstrapping process: 153961b263Sstephan sqlite3-api-prologue.js, whwasmutil.js, and jaccwabyt.js. It 163961b263Sstephan initializes the main API pieces so that the downstream components 173961b263Sstephan (e.g. sqlite3-api-oo1.js) have all that they need. 183961b263Sstephan*/ 19e3cd6760Sstephanself.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ 203961b263Sstephan 'use strict'; 213961b263Sstephan const toss = (...args)=>{throw new Error(args.join(' '))}; 223961b263Sstephan const capi = sqlite3.capi, wasm = capi.wasm, util = capi.util; 233961b263Sstephan self.WhWasmUtilInstaller(capi.wasm); 243961b263Sstephan delete self.WhWasmUtilInstaller; 253961b263Sstephan 263961b263Sstephan if(0){ 273961b263Sstephan /* "The problem" is that the following isn't type-safe. 283961b263Sstephan OTOH, nothing about WASM pointers is. */ 293961b263Sstephan /** 30*d9801185Sstephan Add the `.pointer` xWrap() signature entry to extend the 31*d9801185Sstephan `pointer` arg handler to check for a `pointer` property. This 32*d9801185Sstephan can be used to permit, e.g., passing an sqlite3.oo1.DB instance 33*d9801185Sstephan to a C-style sqlite3_xxx function which takes an `sqlite3*` 34*d9801185Sstephan argument. 353961b263Sstephan */ 363961b263Sstephan const oldP = wasm.xWrap.argAdapter('pointer'); 373961b263Sstephan const adapter = function(v){ 383961b263Sstephan if(v && 'object'===typeof v && v.constructor){ 393961b263Sstephan const x = v.pointer; 403961b263Sstephan if(Number.isInteger(x)) return x; 413961b263Sstephan else toss("Invalid (object) type for pointer-type argument."); 423961b263Sstephan } 433961b263Sstephan return oldP(v); 443961b263Sstephan }; 453961b263Sstephan wasm.xWrap.argAdapter('.pointer', adapter); 46e3cd6760Sstephan } /* ".pointer" xWrap() argument adapter */ 473961b263Sstephan 483961b263Sstephan // WhWasmUtil.xWrap() bindings... 493961b263Sstephan { 503961b263Sstephan /** 513961b263Sstephan Add some descriptive xWrap() aliases for '*' intended to 523961b263Sstephan (A) initially improve readability/correctness of capi.signatures 533961b263Sstephan and (B) eventually perhaps provide some sort of type-safety 543961b263Sstephan in their conversions. 553961b263Sstephan */ 563961b263Sstephan const aPtr = wasm.xWrap.argAdapter('*'); 573961b263Sstephan wasm.xWrap.argAdapter('sqlite3*', aPtr)('sqlite3_stmt*', aPtr); 585b915007Sstephan wasm.xWrap.resultAdapter('sqlite3*', aPtr)('sqlite3_stmt*', aPtr); 593961b263Sstephan 603961b263Sstephan /** 613961b263Sstephan Populate api object with sqlite3_...() by binding the "raw" wasm 623961b263Sstephan exports into type-converting proxies using wasm.xWrap(). 633961b263Sstephan */ 643961b263Sstephan for(const e of wasm.bindingSignatures){ 653961b263Sstephan capi[e[0]] = wasm.xWrap.apply(null, e); 663961b263Sstephan } 6773079dbaSstephan for(const e of wasm.bindingSignatures.wasm){ 6873079dbaSstephan capi.wasm[e[0]] = wasm.xWrap.apply(null, e); 6973079dbaSstephan } 703961b263Sstephan 71e3cd6760Sstephan /* For C API functions which cannot work properly unless 723961b263Sstephan wasm.bigIntEnabled is true, install a bogus impl which 733961b263Sstephan throws if called when bigIntEnabled is false. */ 743961b263Sstephan const fI64Disabled = function(fname){ 753961b263Sstephan return ()=>toss(fname+"() disabled due to lack", 763961b263Sstephan "of BigInt support in this build."); 773961b263Sstephan }; 783961b263Sstephan for(const e of wasm.bindingSignatures.int64){ 793961b263Sstephan capi[e[0]] = wasm.bigIntEnabled 803961b263Sstephan ? wasm.xWrap.apply(null, e) 813961b263Sstephan : fI64Disabled(e[0]); 823961b263Sstephan } 833961b263Sstephan 843961b263Sstephan if(wasm.exports.sqlite3_wasm_db_error){ 853961b263Sstephan util.sqlite3_wasm_db_error = capi.wasm.xWrap( 863961b263Sstephan 'sqlite3_wasm_db_error', 'int', 'sqlite3*', 'int', 'string' 873961b263Sstephan ); 883961b263Sstephan }else{ 893961b263Sstephan util.sqlite3_wasm_db_error = function(pDb,errCode,msg){ 903961b263Sstephan console.warn("sqlite3_wasm_db_error() is not exported.",arguments); 913961b263Sstephan return errCode; 923961b263Sstephan }; 933961b263Sstephan } 943961b263Sstephan 953961b263Sstephan /** 963961b263Sstephan When registering a VFS and its related components it may be 973961b263Sstephan necessary to ensure that JS keeps a reference to them to keep 983961b263Sstephan them from getting garbage collected. Simply pass each such value 993961b263Sstephan to this function and a reference will be held to it for the life 1003961b263Sstephan of the app. 1013961b263Sstephan */ 1023961b263Sstephan capi.sqlite3_vfs_register.addReference = function f(...args){ 1033961b263Sstephan if(!f._) f._ = []; 1043961b263Sstephan f._.push(...args); 1053961b263Sstephan }; 1063961b263Sstephan 1073961b263Sstephan }/*xWrap() bindings*/; 1083961b263Sstephan 1093961b263Sstephan /** 1103961b263Sstephan Scope-local holder of the two impls of sqlite3_prepare_v2/v3(). 1113961b263Sstephan */ 1123961b263Sstephan const __prepare = Object.create(null); 1133961b263Sstephan /** 1143961b263Sstephan This binding expects a JS string as its 2nd argument and 1153961b263Sstephan null as its final argument. In order to compile multiple 1163961b263Sstephan statements from a single string, the "full" impl (see 1173961b263Sstephan below) must be used. 1183961b263Sstephan */ 1193961b263Sstephan __prepare.basic = wasm.xWrap('sqlite3_prepare_v3', 1203961b263Sstephan "int", ["sqlite3*", "string", 121453af2f6Sstephan "int"/*ignored for this impl!*/, 1223961b263Sstephan "int", "**", 1233961b263Sstephan "**"/*MUST be 0 or null or undefined!*/]); 1243961b263Sstephan /** 1253961b263Sstephan Impl which requires that the 2nd argument be a pointer 1263961b263Sstephan to the SQL string, instead of being converted to a 1273961b263Sstephan string. This variant is necessary for cases where we 1283961b263Sstephan require a non-NULL value for the final argument 1293961b263Sstephan (exec()'ing multiple statements from one input 1303961b263Sstephan string). For simpler cases, where only the first 1313961b263Sstephan statement in the SQL string is required, the wrapper 1323961b263Sstephan named sqlite3_prepare_v2() is sufficient and easier to 1333961b263Sstephan use because it doesn't require dealing with pointers. 1343961b263Sstephan */ 1353961b263Sstephan __prepare.full = wasm.xWrap('sqlite3_prepare_v3', 1363961b263Sstephan "int", ["sqlite3*", "*", "int", "int", 1373961b263Sstephan "**", "**"]); 1383961b263Sstephan 1393961b263Sstephan /* Documented in the api object's initializer. */ 1403961b263Sstephan capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){ 1413961b263Sstephan if(util.isSQLableTypedArray(sql)) sql = util.typedArrayToString(sql); 1423961b263Sstephan switch(typeof sql){ 1433961b263Sstephan case 'string': return __prepare.basic(pDb, sql, -1, prepFlags, ppStmt, null); 144453af2f6Sstephan case 'number': return __prepare.full(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail); 1453961b263Sstephan default: 1463961b263Sstephan return util.sqlite3_wasm_db_error( 1473961b263Sstephan pDb, capi.SQLITE_MISUSE, 1483961b263Sstephan "Invalid SQL argument type for sqlite3_prepare_v2/v3()." 1493961b263Sstephan ); 1503961b263Sstephan } 1513961b263Sstephan }; 1523961b263Sstephan 1533961b263Sstephan capi.sqlite3_prepare_v2 = 1543961b263Sstephan (pDb, sql, sqlLen, ppStmt, pzTail)=>capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail); 1553961b263Sstephan 1563961b263Sstephan /** 1573961b263Sstephan Install JS<->C struct bindings for the non-opaque struct types we 1583961b263Sstephan need... */ 1593961b263Sstephan sqlite3.StructBinder = self.Jaccwabyt({ 1603961b263Sstephan heap: 0 ? wasm.memory : wasm.heap8u, 1613961b263Sstephan alloc: wasm.alloc, 1623961b263Sstephan dealloc: wasm.dealloc, 1633961b263Sstephan functionTable: wasm.functionTable, 1643961b263Sstephan bigIntEnabled: wasm.bigIntEnabled, 1653961b263Sstephan memberPrefix: '$' 1663961b263Sstephan }); 1673961b263Sstephan delete self.Jaccwabyt; 1683961b263Sstephan 1693961b263Sstephan {/* Import C-level constants and structs... */ 1703961b263Sstephan const cJson = wasm.xCall('sqlite3_wasm_enum_json'); 1713961b263Sstephan if(!cJson){ 1723961b263Sstephan toss("Maintenance required: increase sqlite3_wasm_enum_json()'s", 1733961b263Sstephan "static buffer size!"); 1743961b263Sstephan } 1753961b263Sstephan wasm.ctype = JSON.parse(wasm.cstringToJs(cJson)); 1763961b263Sstephan //console.debug('wasm.ctype length =',wasm.cstrlen(cJson)); 1773961b263Sstephan for(const t of ['access', 'blobFinalizers', 'dataTypes', 1785b915007Sstephan 'encodings', 'fcntl', 'flock', 'ioCap', 1793961b263Sstephan 'openFlags', 'prepareFlags', 'resultCodes', 1803961b263Sstephan 'syncFlags', 'udfFlags', 'version' 1813961b263Sstephan ]){ 182f75c0c70Sstephan for(const e of Object.entries(wasm.ctype[t])){ 183f75c0c70Sstephan // ^^^ [k,v] there triggers a buggy code transormation via one 184f75c0c70Sstephan // of the Emscripten-driven optimizers. 185f75c0c70Sstephan capi[e[0]] = e[1]; 1863961b263Sstephan } 1873961b263Sstephan } 1881f095d48Sstephan const __rcMap = Object.create(null); 1891f095d48Sstephan for(const t of ['resultCodes']){ 1901f095d48Sstephan for(const e of Object.entries(wasm.ctype[t])){ 1911f095d48Sstephan __rcMap[e[1]] = e[0]; 1921f095d48Sstephan } 1931f095d48Sstephan } 1941f095d48Sstephan /** 1951f095d48Sstephan For the given integer, returns the SQLITE_xxx result code as a 1961f095d48Sstephan string, or undefined if no such mapping is found. 1971f095d48Sstephan */ 1981f095d48Sstephan capi.sqlite3_wasm_rc_str = (rc)=>__rcMap[rc]; 1993961b263Sstephan /* Bind all registered C-side structs... */ 2003961b263Sstephan for(const s of wasm.ctype.structs){ 2013961b263Sstephan capi[s.name] = sqlite3.StructBinder(s); 2023961b263Sstephan } 2031f095d48Sstephan }/*end C constant imports*/ 204e3cd6760Sstephan}); 205