Make explicit which JS APIs are for internal use only by moving the JS-bound internal...
[sqlite.git] / ext / wasm / api / sqlite3-v-helper.js
blobe63da8afc305323f75fc1ffedbc510227f827636
1 /*
2 ** 2022-11-30
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.
12 /**
13    This file installs sqlite3.vfs, and object which exists to assist
14    in the creation of JavaScript implementations of sqlite3_vfs, along
15    with its virtual table counterpart, sqlite3.vtab.
17 'use strict';
18 globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
19   const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
20   const vfs = Object.create(null), vtab = Object.create(null);
22   const StructBinder = sqlite3.StructBinder
23   /* we require a local alias b/c StructBinder is removed from the sqlite3
24      object during the final steps of the API cleanup. */;
25   sqlite3.vfs = vfs;
26   sqlite3.vtab = vtab;
28   const sii = capi.sqlite3_index_info;
29   /**
30      If n is >=0 and less than this.$nConstraint, this function
31      returns either a WASM pointer to the 0-based nth entry of
32      this.$aConstraint (if passed a truthy 2nd argument) or an
33      sqlite3_index_info.sqlite3_index_constraint object wrapping that
34      address (if passed a falsy value or no 2nd argument). Returns a
35      falsy value if n is out of range.
36   */
37   sii.prototype.nthConstraint = function(n, asPtr=false){
38     if(n<0 || n>=this.$nConstraint) return false;
39     const ptr = this.$aConstraint + (
40       sii.sqlite3_index_constraint.structInfo.sizeof * n
41     );
42     return asPtr ? ptr : new sii.sqlite3_index_constraint(ptr);
43   };
45   /**
46      Works identically to nthConstraint() but returns state from
47      this.$aConstraintUsage, so returns an
48      sqlite3_index_info.sqlite3_index_constraint_usage instance
49      if passed no 2nd argument or a falsy 2nd argument.
50   */
51   sii.prototype.nthConstraintUsage = function(n, asPtr=false){
52     if(n<0 || n>=this.$nConstraint) return false;
53     const ptr = this.$aConstraintUsage + (
54       sii.sqlite3_index_constraint_usage.structInfo.sizeof * n
55     );
56     return asPtr ? ptr : new sii.sqlite3_index_constraint_usage(ptr);
57   };
59   /**
60      If n is >=0 and less than this.$nOrderBy, this function
61      returns either a WASM pointer to the 0-based nth entry of
62      this.$aOrderBy (if passed a truthy 2nd argument) or an
63      sqlite3_index_info.sqlite3_index_orderby object wrapping that
64      address (if passed a falsy value or no 2nd argument). Returns a
65      falsy value if n is out of range.
66   */
67   sii.prototype.nthOrderBy = function(n, asPtr=false){
68     if(n<0 || n>=this.$nOrderBy) return false;
69     const ptr = this.$aOrderBy + (
70       sii.sqlite3_index_orderby.structInfo.sizeof * n
71     );
72     return asPtr ? ptr : new sii.sqlite3_index_orderby(ptr);
73   };
75   /**
76      Installs a StructBinder-bound function pointer member of the
77      given name and function in the given StructType target object.
79      It creates a WASM proxy for the given function and arranges for
80      that proxy to be cleaned up when tgt.dispose() is called. Throws
81      on the slightest hint of error, e.g. tgt is-not-a StructType,
82      name does not map to a struct-bound member, etc.
84      As a special case, if the given function is a pointer, then
85      `wasm.functionEntry()` is used to validate that it is a known
86      function. If so, it is used as-is with no extra level of proxying
87      or cleanup, else an exception is thrown. It is legal to pass a
88      value of 0, indicating a NULL pointer, with the caveat that 0
89      _is_ a legal function pointer in WASM but it will not be accepted
90      as such _here_. (Justification: the function at address zero must
91      be one which initially came from the WASM module, not a method we
92      want to bind to a virtual table or VFS.)
94      This function returns a proxy for itself which is bound to tgt
95      and takes 2 args (name,func). That function returns the same
96      thing as this one, permitting calls to be chained.
98      If called with only 1 arg, it has no side effects but returns a
99      func with the same signature as described above.
101      ACHTUNG: because we cannot generically know how to transform JS
102      exceptions into result codes, the installed functions do no
103      automatic catching of exceptions. It is critical, to avoid
104      undefined behavior in the C layer, that methods mapped via
105      this function do not throw. The exception, as it were, to that
106      rule is...
108      If applyArgcCheck is true then each JS function (as opposed to
109      function pointers) gets wrapped in a proxy which asserts that it
110      is passed the expected number of arguments, throwing if the
111      argument count does not match expectations. That is only intended
112      for dev-time usage for sanity checking, and will leave the C
113      environment in an undefined state.
114   */
115   const installMethod = function callee(
116     tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
117   ){
118     if(!(tgt instanceof StructBinder.StructType)){
119       toss("Usage error: target object is-not-a StructType.");
120     }else if(!(func instanceof Function) && !wasm.isPtr(func)){
121       toss("Usage errror: expecting a Function or WASM pointer to one.");
122     }
123     if(1===arguments.length){
124       return (n,f)=>callee(tgt, n, f, applyArgcCheck);
125     }
126     if(!callee.argcProxy){
127       callee.argcProxy = function(tgt, funcName, func,sig){
128         return function(...args){
129           if(func.length!==arguments.length){
130             toss("Argument mismatch for",
131                  tgt.structInfo.name+"::"+funcName
132                  +": Native signature is:",sig);
133           }
134           return func.apply(this, args);
135         }
136       };
137       /* An ondispose() callback for use with
138          StructBinder-created types. */
139       callee.removeFuncList = function(){
140         if(this.ondispose.__removeFuncList){
141           this.ondispose.__removeFuncList.forEach(
142             (v,ndx)=>{
143               if('number'===typeof v){
144                 try{wasm.uninstallFunction(v)}
145                 catch(e){/*ignore*/}
146               }
147               /* else it's a descriptive label for the next number in
148                  the list. */
149             }
150           );
151           delete this.ondispose.__removeFuncList;
152         }
153       };
154     }/*static init*/
155     const sigN = tgt.memberSignature(name);
156     if(sigN.length<2){
157       toss("Member",name,"does not have a function pointer signature:",sigN);
158     }
159     const memKey = tgt.memberKey(name);
160     const fProxy = (applyArgcCheck && !wasm.isPtr(func))
161     /** This middle-man proxy is only for use during development, to
162         confirm that we always pass the proper number of
163         arguments. We know that the C-level code will always use the
164         correct argument count. */
165           ? callee.argcProxy(tgt, memKey, func, sigN)
166           : func;
167     if(wasm.isPtr(fProxy)){
168       if(fProxy && !wasm.functionEntry(fProxy)){
169         toss("Pointer",fProxy,"is not a WASM function table entry.");
170       }
171       tgt[memKey] = fProxy;
172     }else{
173       const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
174       tgt[memKey] = pFunc;
175       if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
176         tgt.addOnDispose('ondispose.__removeFuncList handler',
177                          callee.removeFuncList);
178         tgt.ondispose.__removeFuncList = [];
179       }
180       tgt.ondispose.__removeFuncList.push(memKey, pFunc);
181     }
182     return (n,f)=>callee(tgt, n, f, applyArgcCheck);
183   }/*installMethod*/;
184   installMethod.installMethodArgcCheck = false;
186   /**
187      Installs methods into the given StructType-type instance. Each
188      entry in the given methods object must map to a known member of
189      the given StructType, else an exception will be triggered.  See
190      installMethod() for more details, including the semantics of the
191      3rd argument.
193      As an exception to the above, if any two or more methods in the
194      2nd argument are the exact same function, installMethod() is
195      _not_ called for the 2nd and subsequent instances, and instead
196      those instances get assigned the same method pointer which is
197      created for the first instance. This optimization is primarily to
198      accommodate special handling of sqlite3_module::xConnect and
199      xCreate methods.
201      On success, returns its first argument. Throws on error.
202   */
203   const installMethods = function(
204     structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck
205   ){
206     const seen = new Map /* map of <Function, memberName> */;
207     for(const k of Object.keys(methods)){
208       const m = methods[k];
209       const prior = seen.get(m);
210       if(prior){
211         const mkey = structInstance.memberKey(k);
212         structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
213       }else{
214         installMethod(structInstance, k, m, applyArgcCheck);
215         seen.set(m, k);
216       }
217     }
218     return structInstance;
219   };
221   /**
222      Equivalent to calling installMethod(this,...arguments) with a
223      first argument of this object. If called with 1 or 2 arguments
224      and the first is an object, it's instead equivalent to calling
225      installMethods(this,...arguments).
226   */
227   StructBinder.StructType.prototype.installMethod = function callee(
228     name, func, applyArgcCheck = installMethod.installMethodArgcCheck
229   ){
230     return (arguments.length < 3 && name && 'object'===typeof name)
231       ? installMethods(this, ...arguments)
232       : installMethod(this, ...arguments);
233   };
235   /**
236      Equivalent to calling installMethods() with a first argument
237      of this object.
238   */
239   StructBinder.StructType.prototype.installMethods = function(
240     methods, applyArgcCheck = installMethod.installMethodArgcCheck
241   ){
242     return installMethods(this, methods, applyArgcCheck);
243   };
245   /**
246      Uses sqlite3_vfs_register() to register this
247      sqlite3.capi.sqlite3_vfs. This object must have already been
248      filled out properly. If the first argument is truthy, the VFS is
249      registered as the default VFS, else it is not.
251      On success, returns this object. Throws on error.
252   */
253   capi.sqlite3_vfs.prototype.registerVfs = function(asDefault=false){
254     if(!(this instanceof sqlite3.capi.sqlite3_vfs)){
255       toss("Expecting a sqlite3_vfs-type argument.");
256     }
257     const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0);
258     if(rc){
259       toss("sqlite3_vfs_register(",this,") failed with rc",rc);
260     }
261     if(this.pointer !== capi.sqlite3_vfs_find(this.$zName)){
262       toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS",
263            this);
264     }
265     return this;
266   };
268   /**
269      A wrapper for installMethods() or registerVfs() to reduce
270      installation of a VFS and/or its I/O methods to a single
271      call.
273      Accepts an object which contains the properties "io" and/or
274      "vfs", each of which is itself an object with following properties:
276      - `struct`: an sqlite3.StructType-type struct. This must be a
277        populated (except for the methods) object of type
278        sqlite3_io_methods (for the "io" entry) or sqlite3_vfs (for the
279        "vfs" entry).
281      - `methods`: an object mapping sqlite3_io_methods method names
282        (e.g. 'xClose') to JS implementations of those methods. The JS
283        implementations must be call-compatible with their native
284        counterparts.
286      For each of those object, this function passes its (`struct`,
287      `methods`, (optional) `applyArgcCheck`) properties to
288      installMethods().
290      If the `vfs` entry is set then:
292      - Its `struct` property's registerVfs() is called. The
293        `vfs` entry may optionally have an `asDefault` property, which
294        gets passed as the argument to registerVfs().
296      - If `struct.$zName` is falsy and the entry has a string-type
297        `name` property, `struct.$zName` is set to the C-string form of
298        that `name` value before registerVfs() is called. That string
299        gets added to the on-dispose state of the struct.
301      On success returns this object. Throws on error.
302   */
303   vfs.installVfs = function(opt){
304     let count = 0;
305     const propList = ['io','vfs'];
306     for(const key of propList){
307       const o = opt[key];
308       if(o){
309         ++count;
310         installMethods(o.struct, o.methods, !!o.applyArgcCheck);
311         if('vfs'===key){
312           if(!o.struct.$zName && 'string'===typeof o.name){
313             o.struct.addOnDispose(
314               o.struct.$zName = wasm.allocCString(o.name)
315             );
316           }
317           o.struct.registerVfs(!!o.asDefault);
318         }
319       }
320     }
321     if(!count) toss("Misuse: installVfs() options object requires at least",
322                     "one of:", propList);
323     return this;
324   };
326   /**
327      Internal factory function for xVtab and xCursor impls.
328   */
329   const __xWrapFactory = function(methodName,StructType){
330     return function(ptr,removeMapping=false){
331       if(0===arguments.length) ptr = new StructType;
332       if(ptr instanceof StructType){
333         //T.assert(!this.has(ptr.pointer));
334         this.set(ptr.pointer, ptr);
335         return ptr;
336       }else if(!wasm.isPtr(ptr)){
337         sqlite3.SQLite3Error.toss("Invalid argument to",methodName+"()");
338       }
339       let rc = this.get(ptr);
340       if(removeMapping) this.delete(ptr);
341       return rc;
342     }.bind(new Map);
343   };
345   /**
346      A factory function which implements a simple lifetime manager for
347      mappings between C struct pointers and their JS-level wrappers.
348      The first argument must be the logical name of the manager
349      (e.g. 'xVtab' or 'xCursor'), which is only used for error
350      reporting. The second must be the capi.XYZ struct-type value,
351      e.g. capi.sqlite3_vtab or capi.sqlite3_vtab_cursor.
353      Returns an object with 4 methods: create(), get(), unget(), and
354      dispose(), plus a StructType member with the value of the 2nd
355      argument. The methods are documented in the body of this
356      function.
357   */
358   const StructPtrMapper = function(name, StructType){
359     const __xWrap = __xWrapFactory(name,StructType);
360     /**
361        This object houses a small API for managing mappings of (`T*`)
362        to StructType<T> objects, specifically within the lifetime
363        requirements of sqlite3_module methods.
364     */
365     return Object.assign(Object.create(null),{
366       /** The StructType object for this object's API. */
367       StructType,
368       /**
369          Creates a new StructType object, writes its `pointer`
370          value to the given output pointer, and returns that
371          object. Its intended usage depends on StructType:
373          sqlite3_vtab: to be called from sqlite3_module::xConnect()
374          or xCreate() implementations.
376          sqlite3_vtab_cursor: to be called from xOpen().
378          This will throw if allocation of the StructType instance
379          fails or if ppOut is not a pointer-type value.
380       */
381       create: (ppOut)=>{
382         const rc = __xWrap();
383         wasm.pokePtr(ppOut, rc.pointer);
384         return rc;
385       },
386       /**
387          Returns the StructType object previously mapped to the
388          given pointer using create(). Its intended usage depends
389          on StructType:
391          sqlite3_vtab: to be called from sqlite3_module methods which
392          take a (sqlite3_vtab*) pointer _except_ for
393          xDestroy()/xDisconnect(), in which case unget() or dispose().
395          sqlite3_vtab_cursor: to be called from any sqlite3_module methods
396          which take a `sqlite3_vtab_cursor*` argument except xClose(),
397          in which case use unget() or dispose().
399          Rule to remember: _never_ call dispose() on an instance
400          returned by this function.
401       */
402       get: (pCObj)=>__xWrap(pCObj),
403       /**
404          Identical to get() but also disconnects the mapping between the
405          given pointer and the returned StructType object, such that
406          future calls to this function or get() with the same pointer
407          will return the undefined value. Its intended usage depends
408          on StructType:
410          sqlite3_vtab: to be called from sqlite3_module::xDisconnect() or
411          xDestroy() implementations or in error handling of a failed
412          xCreate() or xConnect().
414          sqlite3_vtab_cursor: to be called from xClose() or during
415          cleanup in a failed xOpen().
417          Calling this method obligates the caller to call dispose() on
418          the returned object when they're done with it.
419       */
420       unget: (pCObj)=>__xWrap(pCObj,true),
421       /**
422          Works like unget() plus it calls dispose() on the
423          StructType object.
424       */
425       dispose: (pCObj)=>{
426         const o = __xWrap(pCObj,true);
427         if(o) o.dispose();
428       }
429     });
430   };
432   /**
433      A lifetime-management object for mapping `sqlite3_vtab*`
434      instances in sqlite3_module methods to capi.sqlite3_vtab
435      objects.
437      The API docs are in the API-internal StructPtrMapper().
438   */
439   vtab.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab);
441   /**
442      A lifetime-management object for mapping `sqlite3_vtab_cursor*`
443      instances in sqlite3_module methods to capi.sqlite3_vtab_cursor
444      objects.
446      The API docs are in the API-internal StructPtrMapper().
447   */
448   vtab.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor);
450   /**
451      Convenience form of creating an sqlite3_index_info wrapper,
452      intended for use in xBestIndex implementations. Note that the
453      caller is expected to call dispose() on the returned object
454      before returning. Though not _strictly_ required, as that object
455      does not own the pIdxInfo memory, it is nonetheless good form.
456   */
457   vtab.xIndexInfo = (pIdxInfo)=>new capi.sqlite3_index_info(pIdxInfo);
459   /**
460      Given an error object, this function returns
461      sqlite3.capi.SQLITE_NOMEM if (e instanceof
462      sqlite3.WasmAllocError), else it returns its
463      second argument. Its intended usage is in the methods
464      of a sqlite3_vfs or sqlite3_module:
466      ```
467      try{
468       let rc = ...
469       return rc;
470      }catch(e){
471        return sqlite3.vtab.exceptionToRc(e, sqlite3.capi.SQLITE_XYZ);
472        // where SQLITE_XYZ is some call-appropriate result code.
473      }
474      ```
475   */
476   /**vfs.exceptionToRc = vtab.exceptionToRc =
477     (e, defaultRc=capi.SQLITE_ERROR)=>(
478       (e instanceof sqlite3.WasmAllocError)
479         ? capi.SQLITE_NOMEM
480         : defaultRc
481     );*/
483   /**
484      Given an sqlite3_module method name and error object, this
485      function returns sqlite3.capi.SQLITE_NOMEM if (e instanceof
486      sqlite3.WasmAllocError), else it returns its second argument. Its
487      intended usage is in the methods of a sqlite3_vfs or
488      sqlite3_module:
490      ```
491      try{
492       let rc = ...
493       return rc;
494      }catch(e){
495        return sqlite3.vtab.xError(
496                 'xColumn', e, sqlite3.capi.SQLITE_XYZ);
497        // where SQLITE_XYZ is some call-appropriate result code.
498      }
499      ```
501      If no 3rd argument is provided, its default depends on
502      the error type:
504      - An sqlite3.WasmAllocError always resolves to capi.SQLITE_NOMEM.
506      - If err is an SQLite3Error then its `resultCode` property
507        is used.
509      - If all else fails, capi.SQLITE_ERROR is used.
511      If xError.errorReporter is a function, it is called in
512      order to report the error, else the error is not reported.
513      If that function throws, that exception is ignored.
514   */
515   vtab.xError = function f(methodName, err, defaultRc){
516     if(f.errorReporter instanceof Function){
517       try{f.errorReporter("sqlite3_module::"+methodName+"(): "+err.message);}
518       catch(e){/*ignored*/}
519     }
520     let rc;
521     if(err instanceof sqlite3.WasmAllocError) rc = capi.SQLITE_NOMEM;
522     else if(arguments.length>2) rc = defaultRc;
523     else if(err instanceof sqlite3.SQLite3Error) rc = err.resultCode;
524     return rc || capi.SQLITE_ERROR;
525   };
526   vtab.xError.errorReporter = 1 ? console.error.bind(console) : false;
528   /**
529      "The problem" with this is that it introduces an outer function with
530      a different arity than the passed-in method callback. That means we
531      cannot do argc validation on these. Additionally, some methods (namely
532      xConnect) may have call-specific error handling. It would be a shame to
533      hard-coded that per-method support in this function.
534   */
535   /** vtab.methodCatcher = function(methodName, method, defaultErrRc=capi.SQLITE_ERROR){
536     return function(...args){
537       try { method(...args); }
538       }catch(e){ return vtab.xError(methodName, e, defaultRc) }
539   };
540   */
542   /**
543      A helper for sqlite3_vtab::xRowid() and xUpdate()
544      implementations. It must be passed the final argument to one of
545      those methods (an output pointer to an int64 row ID) and the
546      value to store at the output pointer's address. Returns the same
547      as wasm.poke() and will throw if the 1st or 2nd arguments
548      are invalid for that function.
550      Example xRowid impl:
552      ```
553      const xRowid = (pCursor, ppRowid64)=>{
554        const c = vtab.xCursor(pCursor);
555        vtab.xRowid(ppRowid64, c.myRowId);
556        return 0;
557      };
558      ```
559   */
560   vtab.xRowid = (ppRowid64, value)=>wasm.poke(ppRowid64, value, 'i64');
562   /**
563      A helper to initialize and set up an sqlite3_module object for
564      later installation into individual databases using
565      sqlite3_create_module(). Requires an object with the following
566      properties:
568      - `methods`: an object containing a mapping of properties with
569        the C-side names of the sqlite3_module methods, e.g. xCreate,
570        xBestIndex, etc., to JS implementations for those functions.
571        Certain special-case handling is performed, as described below.
573      - `catchExceptions` (default=false): if truthy, the given methods
574        are not mapped as-is, but are instead wrapped inside wrappers
575        which translate exceptions into result codes of SQLITE_ERROR or
576        SQLITE_NOMEM, depending on whether the exception is an
577        sqlite3.WasmAllocError. In the case of the xConnect and xCreate
578        methods, the exception handler also sets the output error
579        string to the exception's error string.
581      - OPTIONAL `struct`: a sqlite3.capi.sqlite3_module() instance. If
582        not set, one will be created automatically. If the current
583        "this" is-a sqlite3_module then it is unconditionally used in
584        place of `struct`.
586      - OPTIONAL `iVersion`: if set, it must be an integer value and it
587        gets assigned to the `$iVersion` member of the struct object.
588        If it's _not_ set, and the passed-in `struct` object's `$iVersion`
589        is 0 (the default) then this function attempts to define a value
590        for that property based on the list of methods it has.
592      If `catchExceptions` is false, it is up to the client to ensure
593      that no exceptions escape the methods, as doing so would move
594      them through the C API, leading to undefined
595      behavior. (vtab.xError() is intended to assist in reporting
596      such exceptions.)
598      Certain methods may refer to the same implementation. To simplify
599      the definition of such methods:
601      - If `methods.xConnect` is `true` then the value of
602        `methods.xCreate` is used in its place, and vice versa. sqlite
603        treats xConnect/xCreate functions specially if they are exactly
604        the same function (same pointer value).
606      - If `methods.xDisconnect` is true then the value of
607        `methods.xDestroy` is used in its place, and vice versa.
609      This is to facilitate creation of those methods inline in the
610      passed-in object without requiring the client to explicitly get a
611      reference to one of them in order to assign it to the other
612      one.
614      The `catchExceptions`-installed handlers will account for
615      identical references to the above functions and will install the
616      same wrapper function for both.
618      The given methods are expected to return integer values, as
619      expected by the C API. If `catchExceptions` is truthy, the return
620      value of the wrapped function will be used as-is and will be
621      translated to 0 if the function returns a falsy value (e.g. if it
622      does not have an explicit return). If `catchExceptions` is _not_
623      active, the method implementations must explicitly return integer
624      values.
626      Throws on error. On success, returns the sqlite3_module object
627      (`this` or `opt.struct` or a new sqlite3_module instance,
628      depending on how it's called).
629   */
630   vtab.setupModule = function(opt){
631     let createdMod = false;
632     const mod = (this instanceof capi.sqlite3_module)
633           ? this : (opt.struct || (createdMod = new capi.sqlite3_module()));
634     try{
635       const methods = opt.methods || toss("Missing 'methods' object.");
636       for(const e of Object.entries({
637         // -----^ ==> [k,v] triggers a broken code transformation in
638         // some versions of the emsdk toolchain.
639         xConnect: 'xCreate', xDisconnect: 'xDestroy'
640       })){
641         // Remap X=true to X=Y for certain X/Y combinations
642         const k = e[0], v = e[1];
643         if(true === methods[k]) methods[k] = methods[v];
644         else if(true === methods[v]) methods[v] = methods[k];
645       }
646       if(opt.catchExceptions){
647         const fwrap = function(methodName, func){
648           if(['xConnect','xCreate'].indexOf(methodName) >= 0){
649             return function(pDb, pAux, argc, argv, ppVtab, pzErr){
650               try{return func(...arguments) || 0}
651               catch(e){
652                 if(!(e instanceof sqlite3.WasmAllocError)){
653                   wasm.dealloc(wasm.peekPtr(pzErr));
654                   wasm.pokePtr(pzErr, wasm.allocCString(e.message));
655                 }
656                 return vtab.xError(methodName, e);
657               }
658             };
659           }else{
660             return function(...args){
661               try{return func(...args) || 0}
662               catch(e){
663                 return vtab.xError(methodName, e);
664               }
665             };
666           }
667         };
668         const mnames = [
669           'xCreate', 'xConnect', 'xBestIndex', 'xDisconnect',
670           'xDestroy', 'xOpen', 'xClose', 'xFilter', 'xNext',
671           'xEof', 'xColumn', 'xRowid', 'xUpdate',
672           'xBegin', 'xSync', 'xCommit', 'xRollback',
673           'xFindFunction', 'xRename', 'xSavepoint', 'xRelease',
674           'xRollbackTo', 'xShadowName'
675         ];
676         const remethods = Object.create(null);
677         for(const k of mnames){
678           const m = methods[k];
679           if(!(m instanceof Function)) continue;
680           else if('xConnect'===k && methods.xCreate===m){
681             remethods[k] = methods.xCreate;
682           }else if('xCreate'===k && methods.xConnect===m){
683             remethods[k] = methods.xConnect;
684           }else{
685             remethods[k] = fwrap(k, m);
686           }
687         }
688         installMethods(mod, remethods, false);
689       }else{
690         // No automatic exception handling. Trust the client
691         // to not throw.
692         installMethods(
693           mod, methods, !!opt.applyArgcCheck/*undocumented option*/
694         );
695       }
696       if(0===mod.$iVersion){
697         let v;
698         if('number'===typeof opt.iVersion) v = opt.iVersion;
699         else if(mod.$xShadowName) v = 3;
700         else if(mod.$xSavePoint || mod.$xRelease || mod.$xRollbackTo) v = 2;
701         else v = 1;
702         mod.$iVersion = v;
703       }
704     }catch(e){
705       if(createdMod) createdMod.dispose();
706       throw e;
707     }
708     return mod;
709   }/*setupModule()*/;
711   /**
712      Equivalent to calling vtab.setupModule() with this sqlite3_module
713      object as the call's `this`.
714   */
715   capi.sqlite3_module.prototype.setupModule = function(opt){
716     return vtab.setupModule.call(this, opt);
717   };
718 }/*sqlite3ApiBootstrap.initializers.push()*/);