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