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 capi = sqlite3.capi, wasm = capi.wasm, util = capi.util; 23 self.WhWasmUtilInstaller(capi.wasm); 24 delete self.WhWasmUtilInstaller; 25 26 if(0){ 27 /* "The problem" is that the following isn't type-safe. 28 OTOH, nothing about WASM pointers is. */ 29 /** 30 Add the `.pointer` xWrap() signature entry to extend 31 the `pointer` arg handler to check for a `pointer` 32 property. This can be used to permit, e.g., passing 33 an SQLite3.DB instance to a C-style sqlite3_xxx function 34 which takes an `sqlite3*` argument. 35 */ 36 const oldP = wasm.xWrap.argAdapter('pointer'); 37 const adapter = function(v){ 38 if(v && 'object'===typeof v && v.constructor){ 39 const x = v.pointer; 40 if(Number.isInteger(x)) return x; 41 else toss("Invalid (object) type for pointer-type argument."); 42 } 43 return oldP(v); 44 }; 45 wasm.xWrap.argAdapter('.pointer', adapter); 46 } /* ".pointer" xWrap() argument adapter */ 47 48 // WhWasmUtil.xWrap() bindings... 49 { 50 /** 51 Add some descriptive xWrap() aliases for '*' intended to 52 (A) initially improve readability/correctness of capi.signatures 53 and (B) eventually perhaps provide some sort of type-safety 54 in their conversions. 55 */ 56 const aPtr = wasm.xWrap.argAdapter('*'); 57 wasm.xWrap.argAdapter('sqlite3*', aPtr)('sqlite3_stmt*', aPtr); 58 wasm.xWrap.resultAdapter('sqlite3*', aPtr)('sqlite3_stmt*', aPtr); 59 60 /** 61 Populate api object with sqlite3_...() by binding the "raw" wasm 62 exports into type-converting proxies using wasm.xWrap(). 63 */ 64 for(const e of wasm.bindingSignatures){ 65 capi[e[0]] = wasm.xWrap.apply(null, e); 66 } 67 for(const e of wasm.bindingSignatures.wasm){ 68 capi.wasm[e[0]] = wasm.xWrap.apply(null, e); 69 } 70 71 /* For C API functions which cannot work properly unless 72 wasm.bigIntEnabled is true, install a bogus impl which 73 throws if called when bigIntEnabled is false. */ 74 const fI64Disabled = function(fname){ 75 return ()=>toss(fname+"() disabled due to lack", 76 "of BigInt support in this build."); 77 }; 78 for(const e of wasm.bindingSignatures.int64){ 79 capi[e[0]] = wasm.bigIntEnabled 80 ? wasm.xWrap.apply(null, e) 81 : fI64Disabled(e[0]); 82 } 83 84 if(wasm.exports.sqlite3_wasm_db_error){ 85 util.sqlite3_wasm_db_error = capi.wasm.xWrap( 86 'sqlite3_wasm_db_error', 'int', 'sqlite3*', 'int', 'string' 87 ); 88 }else{ 89 util.sqlite3_wasm_db_error = function(pDb,errCode,msg){ 90 console.warn("sqlite3_wasm_db_error() is not exported.",arguments); 91 return errCode; 92 }; 93 } 94 95 /** 96 When registering a VFS and its related components it may be 97 necessary to ensure that JS keeps a reference to them to keep 98 them from getting garbage collected. Simply pass each such value 99 to this function and a reference will be held to it for the life 100 of the app. 101 */ 102 capi.sqlite3_vfs_register.addReference = function f(...args){ 103 if(!f._) f._ = []; 104 f._.push(...args); 105 }; 106 107 }/*xWrap() bindings*/; 108 109 /** 110 Scope-local holder of the two impls of sqlite3_prepare_v2/v3(). 111 */ 112 const __prepare = Object.create(null); 113 /** 114 This binding expects a JS string as its 2nd argument and 115 null as its final argument. In order to compile multiple 116 statements from a single string, the "full" impl (see 117 below) must be used. 118 */ 119 __prepare.basic = wasm.xWrap('sqlite3_prepare_v3', 120 "int", ["sqlite3*", "string", 121 "int"/*ignored for this impl!*/, 122 "int", "**", 123 "**"/*MUST be 0 or null or undefined!*/]); 124 /** 125 Impl which requires that the 2nd argument be a pointer 126 to the SQL string, instead of being converted to a 127 string. This variant is necessary for cases where we 128 require a non-NULL value for the final argument 129 (exec()'ing multiple statements from one input 130 string). For simpler cases, where only the first 131 statement in the SQL string is required, the wrapper 132 named sqlite3_prepare_v2() is sufficient and easier to 133 use because it doesn't require dealing with pointers. 134 */ 135 __prepare.full = wasm.xWrap('sqlite3_prepare_v3', 136 "int", ["sqlite3*", "*", "int", "int", 137 "**", "**"]); 138 139 /* Documented in the api object's initializer. */ 140 capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){ 141 if(util.isSQLableTypedArray(sql)) sql = util.typedArrayToString(sql); 142 switch(typeof sql){ 143 case 'string': return __prepare.basic(pDb, sql, -1, prepFlags, ppStmt, null); 144 case 'number': return __prepare.full(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail); 145 default: 146 return util.sqlite3_wasm_db_error( 147 pDb, capi.SQLITE_MISUSE, 148 "Invalid SQL argument type for sqlite3_prepare_v2/v3()." 149 ); 150 } 151 }; 152 153 capi.sqlite3_prepare_v2 = 154 (pDb, sql, sqlLen, ppStmt, pzTail)=>capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail); 155 156 /** 157 Install JS<->C struct bindings for the non-opaque struct types we 158 need... */ 159 sqlite3.StructBinder = self.Jaccwabyt({ 160 heap: 0 ? wasm.memory : wasm.heap8u, 161 alloc: wasm.alloc, 162 dealloc: wasm.dealloc, 163 functionTable: wasm.functionTable, 164 bigIntEnabled: wasm.bigIntEnabled, 165 memberPrefix: '$' 166 }); 167 delete self.Jaccwabyt; 168 169 {/* Import C-level constants and structs... */ 170 const cJson = wasm.xCall('sqlite3_wasm_enum_json'); 171 if(!cJson){ 172 toss("Maintenance required: increase sqlite3_wasm_enum_json()'s", 173 "static buffer size!"); 174 } 175 wasm.ctype = JSON.parse(wasm.cstringToJs(cJson)); 176 //console.debug('wasm.ctype length =',wasm.cstrlen(cJson)); 177 for(const t of ['access', 'blobFinalizers', 'dataTypes', 178 'encodings', 'fcntl', 'flock', 'ioCap', 179 'openFlags', 'prepareFlags', 'resultCodes', 180 'syncFlags', 'udfFlags', 'version' 181 ]){ 182 for(const e of Object.entries(wasm.ctype[t])){ 183 // ^^^ [k,v] there triggers a buggy code transormation via one 184 // of the Emscripten-driven optimizers. 185 capi[e[0]] = e[1]; 186 } 187 } 188 const __rcMap = Object.create(null); 189 for(const t of ['resultCodes']){ 190 for(const e of Object.entries(wasm.ctype[t])){ 191 __rcMap[e[1]] = e[0]; 192 } 193 } 194 /** 195 For the given integer, returns the SQLITE_xxx result code as a 196 string, or undefined if no such mapping is found. 197 */ 198 capi.sqlite3_wasm_rc_str = (rc)=>__rcMap[rc]; 199 /* Bind all registered C-side structs... */ 200 for(const s of wasm.ctype.structs){ 201 capi[s.name] = sqlite3.StructBinder(s); 202 } 203 }/*end C constant imports*/ 204}); 205