]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Reorganization and renaming in the new VFS/vtab JS pieces.
authorstephan <stephan@noemail.net>
Fri, 9 Dec 2022 00:50:39 +0000 (00:50 +0000)
committerstephan <stephan@noemail.net>
Fri, 9 Dec 2022 00:50:39 +0000 (00:50 +0000)
FossilOrigin-Name: 1c2dda177a11fcc5b66e5554507c23ba4b9948a710b3bccfb26963b9851d40a4

ext/wasm/api/sqlite3-v-helper.js
ext/wasm/api/sqlite3-vfs-opfs.c-pp.js
ext/wasm/tester1.c-pp.js
manifest
manifest.uuid

index 25f71556a6cd1f4f2e8dbe7affd192c81bc3dcc3..a1a34c3fa53fc1c949ac43248ad7a67c5885be13 100644 (file)
 'use strict';
 self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
   const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
-  const vh = Object.create(null), vt = Object.create(null);
+  const vfs = Object.create(null), vtab = Object.create(null);
 
-  sqlite3.VfsHelper = vh;
-  sqlite3.VtabHelper = vt;
+  sqlite3.vfs = vfs;
+  sqlite3.vtab = vtab;
 
   const sii = capi.sqlite3_index_info;
   /**
@@ -78,15 +78,15 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      on the slightest hint of error, e.g. tgt is-not-a StructType,
      name does not map to a struct-bound member, etc.
 
-     As a special case, if the given function is a pointer, it is
-     assumed to be an existing WASM-bound function pointer and is used
-     as-is with no extra level of proxying or cleanup. Results are
-     undefined if it's a pointer and it's _not_ a function pointer.
-     It is legal to pass a value of 0, indicating a NULL pointer, with
-     the caveat that 0 _is_ a legal function pointer in WASM but it
-     will not be accepted as such _here_. (Justification: the function
-     at address zero must be one which initially came from the WASM
-     module, not a method we want to bind to a virtual table or VFS.)
+     As a special case, if the given function is a pointer, then
+     `wasm.functionEntry()` is used to validate that it is a known
+     function. If so, it is used as-is with no extra level of proxying
+     or cleanup, else an exception is thrown. It is legal to pass a
+     value of 0, indicating a NULL pointer, with the caveat that 0
+     _is_ a legal function pointer in WASM but it will not be accepted
+     as such _here_. (Justification: the function at address zero must
+     be one which initially came from the WASM module, not a method we
+     want to bind to a virtual table or VFS.)
 
      This function returns a proxy for itself which is bound to tgt
      and takes 2 args (name,func). That function returns the same
@@ -109,7 +109,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      for dev-time usage for sanity checking, and will leave the C
      environment in an undefined state.
   */
-  vh.installMethod = vt.installMethod = function callee(
+  const installMethod = function callee(
     tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
   ){
     if(!(tgt instanceof sqlite3.StructBinder.StructType)){
@@ -169,8 +169,6 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     }else{
       const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
       tgt[memKey] = pFunc;
-      if(!tgt.ondispose) tgt.ondispose = [];
-      else if(!Array.isArray(tgt.ondispose)) tgt.ondispose = [tgt.ondispose];
       if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
         tgt.addOnDispose('ondispose.__removeFuncList handler',
                          callee.removeFuncList);
@@ -180,7 +178,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     }
     return (n,f)=>callee(tgt, n, f, applyArgcCheck);
   }/*installMethod*/;
-  vh.installMethod.installMethodArgcCheck = false;
+  installMethod.installMethodArgcCheck = false;
 
   /**
      Installs methods into the given StructType-type instance. Each
@@ -197,45 +195,69 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      accommodate special handling of sqlite3_module::xConnect and
      xCreate methods.
 
-     On success, returns this object. Throws on error.
+     On success, returns its first argument. Throws on error.
   */
-  vh.installMethods = vt.installMethods = function(
-    structType, methods, applyArgcCheck = vh.installMethod.installMethodArgcCheck
+  const installMethods = function(
+    structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck
   ){
     const seen = new Map /* map of <Function, memberName> */;
     for(const k of Object.keys(methods)){
       const m = methods[k];
       const prior = seen.get(m);
       if(prior){
-        const mkey = structType.memberKey(k);
-        structType[mkey] = structType[structType.memberKey(prior)];
+        const mkey = structInstance.memberKey(k);
+        structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
       }else{
-        vh.installMethod(structType, k, m, applyArgcCheck);
+        installMethod(structInstance, k, m, applyArgcCheck);
         seen.set(m, k);
       }
     }
-    return this;
+    return structInstance;
   };
 
   /**
-     Uses sqlite3_vfs_register() to register the
-     sqlite3.capi.sqlite3_vfs-type vfs, which must have already been
-     filled out properly. If the 2nd argument is truthy, the VFS is
+     Equivalent to calling installMethod(this,...arguments) with a
+     first argument of this object. If called with 1 or 2 arguments
+     and the first is an object, it's instead equivalent to calling
+     installMethods(this,...arguments).
+  */
+  sqlite3.StructBinder.StructType.prototype.installMethod = function callee(
+    name, func, applyArgcCheck = installMethod.installMethodArgcCheck
+  ){
+    return (arguments.length < 3 && name && 'object'===typeof name)
+      ? installMethods(this, ...arguments)
+      : installMethod(this, ...arguments);
+  };
+
+  /**
+     Equivalent to calling installMethods() with a first argument
+     of this object.
+  */
+  sqlite3.StructBinder.StructType.prototype.installMethods = function(
+    methods, applyArgcCheck = installMethod.installMethodArgcCheck
+  ){
+    return installMethods(this, methods, applyArgcCheck);
+  };
+
+  /**
+     Uses sqlite3_vfs_register() to register this
+     sqlite3.capi.sqlite3_vfs. This object must have already been
+     filled out properly. If the first argument is truthy, the VFS is
      registered as the default VFS, else it is not.
 
      On success, returns this object. Throws on error.
   */
-  vh.registerVfs = function(vfs, asDefault=false){
-    if(!(vfs instanceof sqlite3.capi.sqlite3_vfs)){
+  capi.sqlite3_vfs.prototype.registerVfs = function(asDefault=false){
+    if(!(this instanceof sqlite3.capi.sqlite3_vfs)){
       toss("Expecting a sqlite3_vfs-type argument.");
     }
-    const rc = capi.sqlite3_vfs_register(vfs.pointer, asDefault ? 1 : 0);
+    const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0);
     if(rc){
-      toss("sqlite3_vfs_register(",vfs,") failed with rc",rc);
+      toss("sqlite3_vfs_register(",this,") failed with rc",rc);
     }
-    if(vfs.pointer !== capi.sqlite3_vfs_find(vfs.$zName)){
+    if(this.pointer !== capi.sqlite3_vfs_find(this.$zName)){
       toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS",
-           vfs);
+           this);
     }
     return this;
   };
@@ -260,13 +282,13 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
 
      For each of those object, this function passes its (`struct`,
      `methods`, (optional) `applyArgcCheck`) properties to
-     this.installMethods().
+     installMethods().
 
      If the `vfs` entry is set then:
 
-     - Its `struct` property is passed to this.registerVfs(). The
+     - Its `struct` property's registerVfs() is called. The
        `vfs` entry may optionally have an `asDefault` property, which
-       gets passed as the 2nd argument to registerVfs().
+       gets passed as the argument to registerVfs().
 
      - If `struct.$zName` is falsy and the entry has a string-type
        `name` property, `struct.$zName` is set to the C-string form of
@@ -274,21 +296,21 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
 
      On success returns this object. Throws on error.
   */
-  vh.installVfs = function(opt){
+  vfs.installVfs = function(opt){
     let count = 0;
     const propList = ['io','vfs'];
     for(const key of propList){
       const o = opt[key];
       if(o){
         ++count;
-        this.installMethods(o.struct, o.methods, !!o.applyArgcCheck);
+        installMethods(o.struct, o.methods, !!o.applyArgcCheck);
         if('vfs'===key){
           if(!o.struct.$zName && 'string'===typeof o.name){
             o.struct.addOnDispose(
               o.struct.$zName = wasm.allocCString(o.name)
             );
           }
-          this.registerVfs(o.struct, !!o.asDefault);
+          o.struct.registerVfs(!!o.asDefault);
         }
       }
     }
@@ -305,7 +327,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      as sqlite3_create_function_v2() and friends. Throws on error,
      e.g. if it cannot figure out a sensible data conversion.
   */
-  vt.sqlite3ValuesToJs = capi.sqlite3_create_function_v2.udfConvertArgs;
+  vtab.sqlite3ValuesToJs = capi.sqlite3_create_function_v2.udfConvertArgs;
 
   /**
      Internal factory function for xVtab and xCursor impls.
@@ -414,7 +436,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
 
      The API docs are in the API-internal StructPtrMapper().
   */
-  vt.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab);
+  vtab.xVtab = StructPtrMapper('xVtab', capi.sqlite3_vtab);
 
   /**
      A lifetime-management object for mapping `sqlite3_vtab_cursor*`
@@ -423,7 +445,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
 
      The API docs are in the API-internal StructPtrMapper().
   */
-  vt.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor);
+  vtab.xCursor = StructPtrMapper('xCursor', capi.sqlite3_vtab_cursor);
 
   /**
      Convenience form of creating an sqlite3_index_info wrapper,
@@ -432,7 +454,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      before returning. Though not _strictly_ required, as that object
      does not own the pIdxInfo memory, it is nonetheless good form.
   */
-  vt.xIndexInfo = (pIdxInfo)=>new capi.sqlite3_index_info(pIdxInfo);
+  vtab.xIndexInfo = (pIdxInfo)=>new capi.sqlite3_index_info(pIdxInfo);
 
   /**
      Given an error object, this function returns
@@ -451,7 +473,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      }
      ```
   */
-  /**vh.exceptionToRc = vt.exceptionToRc =
+  /**vfs.exceptionToRc = vtab.exceptionToRc =
     (e, defaultRc=capi.SQLITE_ERROR)=>(
       (e instanceof sqlite3.WasmAllocError)
         ? capi.SQLITE_NOMEM
@@ -490,7 +512,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      order to report the error, else the error is not reported.
      If that function throws, that exception is ignored.
   */
-  vt.xError = function f(methodName, err, defaultRc){
+  vtab.xError = function f(methodName, err, defaultRc){
     if(f.errorReporter instanceof Function){
       try{f.errorReporter("sqlite3_module::"+methodName+"(): "+err.message);}
       catch(e){/*ignored*/}
@@ -501,7 +523,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     else if(err instanceof sqlite3.SQLite3Error) rc = err.resultCode;
     return rc || capi.SQLITE_ERROR;
   };
-  vt.xError.errorReporter = 1 ? console.error.bind(console) : false;
+  vtab.xError.errorReporter = 1 ? console.error.bind(console) : false;
 
   /**
      "The problem" with this is that it introduces an outer function with
@@ -510,10 +532,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      xConnect) may have call-specific error handling. It would be a shame to
      hard-coded that per-method support in this function.
   */
-  /** vt.methodCatcher = function(methodName, method, defaultErrRc=capi.SQLITE_ERROR){
+  /** vtab.methodCatcher = function(methodName, method, defaultErrRc=capi.SQLITE_ERROR){
     return function(...args){
       try { method(...args); }
-      }catch(e){ return vt.xError(methodName, e, defaultRc) }
+      }catch(e){ return vtab.xError(methodName, e, defaultRc) }
   };
   */
 
@@ -534,10 +556,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      };
      ```
   */
-  vt.xRowid = (ppRowid64, value)=>wasm.setMemValue(ppRowid64, value, 'i64');
+  vtab.xRowid = (ppRowid64, value)=>wasm.setMemValue(ppRowid64, value, 'i64');
 
   /**
-     A helper to initialize and set up an sqlite3_module() object for
+     A helper to initialize and set up an sqlite3_module object for
      later installation into individual databases using
      sqlite3_create_module(). Requires an object with the following
      properties:
@@ -556,8 +578,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
        string to the exception's error string.
 
      - OPTIONAL `struct`: a sqlite3.capi.sqlite3_module() instance. If
-       not set, one will be created automatically and (on success)
-       added to the object.
+       not set, one will be created automatically. If the current
+       "this" is-a sqlite3_module then it is unconditionally used in
+       place of `struct`.
 
      - OPTIONAL `iVersion`: if set, it must be an integer value and it
        gets assigned to the `$iVersion` member of the struct object.
@@ -599,35 +622,44 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      active, the method implementations must explicitly return integer
      values.
 
-     Throws on error. Returns the opt.struct sqlite3_module object on
-     success.
+     Throws on error. On success, returns the sqlite3_module object
+     (`this` or `opt.struct` or a new sqlite3_module instance,
+     depending on how it's called).
   */
-  vt.setupModule = function(opt){
-    const mod = opt.struct || new capi.sqlite3_module();
+  vtab.setupModule = function(opt){
+    let createdMod = false;
+    const mod = (this instanceof capi.sqlite3_module)
+          ? this : (opt.struct || (createdMod = new capi.sqlite3_module()));
     try{
       const methods = opt.methods || toss("Missing 'methods' object.");
-      if(true===methods.xConnect) methods.xConnect = methods.xCreate;
-      else if(true===methods.xCreate) methods.xCreate = methods.xConnect;
-      if(true===methods.xDisconnect) methods.xDisconnect = methods.xDestroy;
-      else if(true===methods.xDestroy) methods.xDestroy = methods.xDisconnect;
+      for(const e of Object.entries({
+        // -----^ ==> [k,v] triggers a broken code transformation in
+        // some versions of the emsdk toolchain.
+        xConnect: 'xCreate', xDisconnect: 'xDestroy'
+      })){
+        // Remap X=true to X=Y for certain X/Y combinations
+        const k = e[0], v = e[1];
+        if(true === methods[k]) methods[k] = methods[v];
+        else if(true === methods[v]) methods[v] = methods[k];
+      }
       if(opt.catchExceptions){
         const fwrap = function(methodName, func){
           if(['xConnect','xCreate'].indexOf(methodName) >= 0){
             return function(pDb, pAux, argc, argv, ppVtab, pzErr){
-              try{return func(...arguments) || 0;}
+              try{return func(...arguments) || 0}
               catch(e){
                 if(!(e instanceof sqlite3.WasmAllocError)){
                   wasm.dealloc(wasm.getPtrValue(pzErr));
                   wasm.setPtrValue(pzErr, wasm.allocCString(e.message));
                 }
-                return vt.xError(methodName, e);
+                return vtab.xError(methodName, e);
               }
             };
           }else{
             return function(...args){
-              try{return func(...args) || 0;}
+              try{return func(...args) || 0}
               catch(e){
-                return vt.xError(methodName, e);
+                return vtab.xError(methodName, e);
               }
             };
           }
@@ -652,11 +684,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
             remethods[k] = fwrap(k, m);
           }
         }
-        this.installMethods(mod, remethods, false);
+        installMethods(mod, remethods, false);
       }else{
         // No automatic exception handling. Trust the client
         // to not throw.
-        this.installMethods(
+        installMethods(
           mod, methods, !!opt.applyArgcCheck/*undocumented option*/
         );
       }
@@ -669,10 +701,17 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
         mod.$iVersion = v;
       }
     }catch(e){
-      if(!opt.struct) mod.dispose();
+      if(createdMod) createdMod.dispose();
       throw e;
     }
-    if(!opt.struct) opt.struct = mod;
     return mod;
   }/*setupModule()*/;
+
+  /**
+     Equivalent to calling vtab.setupModule() with this sqlite3_module
+     object as the call's `this`.
+  */
+  capi.sqlite3_module.prototype.setupModule = function(opt){
+    return vtab.setupModule.call(this, opt);
+  };
 }/*sqlite3ApiBootstrap.initializers.push()*/);
index 49ebfbd80bd3020730293eb960902d541f748484..ea8bc9b2995d35abff600f18eb93edcf9caf5e51 100644 (file)
@@ -1268,7 +1268,7 @@ const installOpfsVfs = function callee(options){
               and has finished initializing, so the real work can
               begin...*/
             try {
-              sqlite3.VfsHelper.installVfs({
+              sqlite3.vfs.installVfs({
                 io: {struct: opfsIoMethods, methods: ioSyncWrappers},
                 vfs: {struct: opfsVfs, methods: vfsSyncWrappers}
               });
index c8225568d55fde98e99fe9e505971ecc23a2a1a0..e57f1c002df6c7fa7c3c0a495ed8fcc572bbcbeb 100644 (file)
@@ -1676,7 +1676,7 @@ self.sqlite3InitModule = sqlite3InitModule;
       predicate: ()=>!!capi.sqlite3_index_info,
       test: function(sqlite3){
         warn("The vtab/module JS bindings are experimental and subject to change.");
-        const vth = sqlite3.VtabHelper;
+        const VT = sqlite3.vtab;
         const tmplCols = Object.assign(Object.create(null),{
           A: 0, B: 1
         });
@@ -1684,195 +1684,178 @@ self.sqlite3InitModule = sqlite3InitModule;
            The vtab demonstrated here is a JS-ification of
            ext/misc/templatevtab.c.
         */
-        const tmplMethods = {
-          xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){
-            try{
-              const args = wasm.cArgvToJs(argc, argv);
-              T.assert(args.length>=3)
-                .assert(args[0] === 'testvtab')
-                .assert(args[1] === 'main')
-                .assert(args[2] === 'testvtab');
-              console.debug("xConnect() args =",args);
-              const rc = capi.sqlite3_declare_vtab(
-                pDb, "CREATE TABLE ignored(a,b)"
-              );
-              if(0===rc){
-                const t = vth.xVtab.create(ppVtab);
-                T.assert(t === vth.xVtab.get(wasm.getPtrValue(ppVtab)));
+        const tmplMod = (new sqlite3.capi.sqlite3_module()).setupModule({
+          catchExceptions: false,
+          methods: {
+            xConnect: function(pDb, pAux, argc, argv, ppVtab, pzErr){
+              try{
+                const args = wasm.cArgvToJs(argc, argv);
+                T.assert(args.length>=3)
+                  .assert(args[0] === 'testvtab')
+                  .assert(args[1] === 'main')
+                  .assert(args[2] === 'testvtab');
+                console.debug("xConnect() args =",args);
+                const rc = capi.sqlite3_declare_vtab(
+                  pDb, "CREATE TABLE ignored(a,b)"
+                );
+                if(0===rc){
+                  const t = VT.xVtab.create(ppVtab);
+                  T.assert(t === VT.xVtab.get(wasm.getPtrValue(ppVtab)));
+                }
+                return rc;
+              }catch(e){
+                if(!(e instanceof sqlite3.WasmAllocError)){
+                  wasm.dealloc(wasm.getPtrValue, pzErr);
+                  wasm.setPtrValue(pzErr, wasm.allocCString(e.message));
+                }
+                return VT.xError('xConnect',e);
               }
-              return rc;
-            }catch(e){
-              if(!(e instanceof sqlite3.WasmAllocError)){
-                wasm.dealloc(wasm.getPtrValue, pzErr);
-                wasm.setPtrValue(pzErr, wasm.allocCString(e.message));
+            },
+            xCreate: true /* just for testing. Will be removed afterwards. */,
+            xDisconnect: function(pVtab){
+              try {
+                VT.xVtab.unget(pVtab).dispose();
+                return 0;
+              }catch(e){
+                return VT.xError('xDisconnect',e);
               }
-              return vth.xError('xConnect',e);
-            }
-          },
-          xDisconnect: function(pVtab){
-            try {
-              vth.xVtab.unget(pVtab).dispose();
-              return 0;
-            }catch(e){
-              return vth.xError('xDisconnect',e);
-            }
-          },
-          xOpen: function(pVtab, ppCursor){
-            try{
-              const t = vth.xVtab.get(pVtab),
-                    c = vth.xCursor.create(ppCursor);
-              T.assert(t instanceof capi.sqlite3_vtab)
-                .assert(c instanceof capi.sqlite3_vtab_cursor);
-              c._rowId = 0;
-              return 0;
-            }catch(e){
-              return vth.xError('xOpen',e);
-            }
-          },
-          xClose: function(pCursor){
-            try{
-              const c = vth.xCursor.unget(pCursor);
-              T.assert(c instanceof capi.sqlite3_vtab_cursor)
-                .assert(!vth.xCursor.get(pCursor));
-              c.dispose();
-              return 0;
-            }catch(e){
-              return vth.xError('xClose',e);
-            }
-          },
-          xNext: function(pCursor){
-            try{
-              const c = vth.xCursor.get(pCursor);
-              ++c._rowId;
-              return 0;
-            }catch(e){
-              return vth.xError('xNext',e);
-            }
-          },
-          xColumn: function(pCursor, pCtx, iCol){
-            try{
-              const c = vth.xCursor.get(pCursor);
-              switch(iCol){
-                  case tmplCols.A:
-                    capi.sqlite3_result_int(pCtx, 1000 + c._rowId);
-                    break;
-                  case tmplCols.B:
-                    capi.sqlite3_result_int(pCtx, 2000 + c._rowId);
-                    break;
-                  default: sqlite3.SQLite3Error.toss("Invalid column id",iCol);
+            },
+            xOpen: function(pVtab, ppCursor){
+              try{
+                const t = VT.xVtab.get(pVtab),
+                      c = VT.xCursor.create(ppCursor);
+                T.assert(t instanceof capi.sqlite3_vtab)
+                  .assert(c instanceof capi.sqlite3_vtab_cursor);
+                c._rowId = 0;
+                return 0;
+              }catch(e){
+                return VT.xError('xOpen',e);
               }
-              return 0;
-            }catch(e){
-              return vth.xError('xColumn',e);
-            }
-          },
-          xRowid: function(pCursor, ppRowid64){
-            try{
-              const c = vth.xCursor.get(pCursor);
-              vth.xRowid(ppRowid64, c._rowId);
-              return 0;
-            }catch(e){
-              return vth.xError('xRowid',e);
-            }
-          },
-          xEof: function(pCursor){
-            const c = vth.xCursor.get(pCursor),
-                  rc = c._rowId>=10;
-            c.dispose();
-            return rc;
-          },
-          xFilter: function(pCursor, idxNum, idxCStr,
-                            argc, argv/* [sqlite3_value* ...] */){
-            try{
-              const c = vth.xCursor.get(pCursor);
-              c._rowId = 0;
-              const list = vth.sqlite3ValuesToJs(argc, argv);
-              T.assert(argc === list.length);
-              //log(argc,"xFilter value(s):",list);
-              c.dispose();
-              return 0;
-            }catch(e){
-              return vth.xError('xFilter',e);
-            }
-          },
-          xBestIndex: function(pVtab, pIdxInfo){
-            try{
-              //const t = vth.xVtab.get(pVtab);
-              const sii = capi.sqlite3_index_info;
-              const pii = new sii(pIdxInfo);
-              pii.$estimatedRows = 10;
-              pii.$estimatedCost = 10.0;
-              //log("xBestIndex $nConstraint =",pii.$nConstraint);
-              if(pii.$nConstraint>0){
-                // Validate nthConstraint() and nthConstraintUsage()
-                const max = pii.$nConstraint;
-                for(let i=0; i < max; ++i ){
-                  let v = pii.nthConstraint(i,true);
-                  T.assert(wasm.isPtr(v));
-                  v = pii.nthConstraint(i);
-                  T.assert(v instanceof sii.sqlite3_index_constraint)
-                    .assert(v.pointer >= pii.$aConstraint);
-                  v.dispose();
-                  v = pii.nthConstraintUsage(i,true);
-                  T.assert(wasm.isPtr(v));
-                  v = pii.nthConstraintUsage(i);
-                  T.assert(v instanceof sii.sqlite3_index_constraint_usage)
-                    .assert(v.pointer >= pii.$aConstraintUsage);
-                  v.$argvIndex = i;//just to get some values into xFilter
-                  v.dispose();
+            },
+            xClose: function(pCursor){
+              try{
+                const c = VT.xCursor.unget(pCursor);
+                T.assert(c instanceof capi.sqlite3_vtab_cursor)
+                  .assert(!VT.xCursor.get(pCursor));
+                c.dispose();
+                return 0;
+              }catch(e){
+                return VT.xError('xClose',e);
+              }
+            },
+            xNext: function(pCursor){
+              try{
+                const c = VT.xCursor.get(pCursor);
+                ++c._rowId;
+                return 0;
+              }catch(e){
+                return VT.xError('xNext',e);
+              }
+            },
+            xColumn: function(pCursor, pCtx, iCol){
+              try{
+                const c = VT.xCursor.get(pCursor);
+                switch(iCol){
+                    case tmplCols.A:
+                      capi.sqlite3_result_int(pCtx, 1000 + c._rowId);
+                      break;
+                    case tmplCols.B:
+                      capi.sqlite3_result_int(pCtx, 2000 + c._rowId);
+                      break;
+                    default: sqlite3.SQLite3Error.toss("Invalid column id",iCol);
                 }
+                return 0;
+              }catch(e){
+                return VT.xError('xColumn',e);
               }
-              //log("xBestIndex $nOrderBy =",pii.$nOrderBy);
-              if(pii.$nOrderBy>0){
-                // Validate nthOrderBy()
-                const max = pii.$nOrderBy;
-                for(let i=0; i < max; ++i ){
-                  let v = pii.nthOrderBy(i,true);
-                  T.assert(wasm.isPtr(v));
-                  v = pii.nthOrderBy(i);
-                  T.assert(v instanceof sii.sqlite3_index_orderby)
-                    .assert(v.pointer >= pii.$aOrderBy);
-                  v.dispose();
+            },
+            xRowid: function(pCursor, ppRowid64){
+              try{
+                const c = VT.xCursor.get(pCursor);
+                VT.xRowid(ppRowid64, c._rowId);
+                return 0;
+              }catch(e){
+                return VT.xError('xRowid',e);
+              }
+            },
+            xEof: function(pCursor){
+              const c = VT.xCursor.get(pCursor),
+                    rc = c._rowId>=10;
+              c.dispose();
+              return rc;
+            },
+            xFilter: function(pCursor, idxNum, idxCStr,
+                              argc, argv/* [sqlite3_value* ...] */){
+              try{
+                const c = VT.xCursor.get(pCursor);
+                c._rowId = 0;
+                const list = VT.sqlite3ValuesToJs(argc, argv);
+                T.assert(argc === list.length);
+                //log(argc,"xFilter value(s):",list);
+                c.dispose();
+                return 0;
+              }catch(e){
+                return VT.xError('xFilter',e);
+              }
+            },
+            xBestIndex: function(pVtab, pIdxInfo){
+              try{
+                //const t = VT.xVtab.get(pVtab);
+                const sii = capi.sqlite3_index_info;
+                const pii = new sii(pIdxInfo);
+                pii.$estimatedRows = 10;
+                pii.$estimatedCost = 10.0;
+                //log("xBestIndex $nConstraint =",pii.$nConstraint);
+                if(pii.$nConstraint>0){
+                  // Validate nthConstraint() and nthConstraintUsage()
+                  const max = pii.$nConstraint;
+                  for(let i=0; i < max; ++i ){
+                    let v = pii.nthConstraint(i,true);
+                    T.assert(wasm.isPtr(v));
+                    v = pii.nthConstraint(i);
+                    T.assert(v instanceof sii.sqlite3_index_constraint)
+                      .assert(v.pointer >= pii.$aConstraint);
+                    v.dispose();
+                    v = pii.nthConstraintUsage(i,true);
+                    T.assert(wasm.isPtr(v));
+                    v = pii.nthConstraintUsage(i);
+                    T.assert(v instanceof sii.sqlite3_index_constraint_usage)
+                      .assert(v.pointer >= pii.$aConstraintUsage);
+                    v.$argvIndex = i;//just to get some values into xFilter
+                    v.dispose();
+                  }
+                }
+                //log("xBestIndex $nOrderBy =",pii.$nOrderBy);
+                if(pii.$nOrderBy>0){
+                  // Validate nthOrderBy()
+                  const max = pii.$nOrderBy;
+                  for(let i=0; i < max; ++i ){
+                    let v = pii.nthOrderBy(i,true);
+                    T.assert(wasm.isPtr(v));
+                    v = pii.nthOrderBy(i);
+                    T.assert(v instanceof sii.sqlite3_index_orderby)
+                      .assert(v.pointer >= pii.$aOrderBy);
+                    v.dispose();
+                  }
                 }
+                pii.dispose();
+                return 0;
+              }catch(e){
+                return VT.xError('xBestIndex',e);
               }
-              pii.dispose();
-              return 0;
-            }catch(e){
-              return vth.xError('xBestIndex',e);
             }
           }
-        };
-        /**
-           The vtab API places relevance on whether xCreate and
-           xConnect are exactly the same function (same pointer
-           address). Two JS-side references to the same method will
-           end up, without acrobatics to counter it, being compiled as
-           two different WASM-side bindings, i.e. two different
-           pointers.
-
-           In order to account for this, VtabHelper.installMethods()
-           checks for duplicate function entries and maps them to the
-           same WASM-compiled instance.
-        */
-        if(1){
-          tmplMethods.xCreate = tmplMethods.xConnect;
-        }
-
-        const tmplMod = new sqlite3.capi.sqlite3_module();
-        tmplMod.$iVersion = 0;
+        });
         this.db.onclose.disposeAfter.push(tmplMod);
-        vth.installMethods(tmplMod, tmplMethods, true);
-        if(tmplMethods.xCreate){
-          T.assert(tmplMod.$xCreate)
-            .assert(tmplMod.$xCreate === tmplMod.$xConnect,
-                    "installMethods() must avoid re-compiling identical functions");
-          tmplMod.$xCreate = 0;
-        }
+        T.assert(tmplMod.$xCreate)
+          .assert(tmplMod.$xCreate === tmplMod.$xConnect,
+                  "setup() must make these equivalent and "+
+                  "installMethods() must avoid re-compiling identical functions");
+        tmplMod.$xCreate = 0 /* make tmplMod eponymous-only */;
         let rc = capi.sqlite3_create_module(
           this.db, "testvtab", tmplMod, 0
         );
         this.db.checkRc(rc);
-
         const list = this.db.selectArrays(
           "SELECT a,b FROM testvtab where a<9999 and b>1 order by a, b"
           /* Query is shaped so that it will ensure that some constraints
@@ -1890,7 +1873,7 @@ self.sqlite3InitModule = sqlite3InitModule;
       predicate: ()=>!!capi.sqlite3_index_info,
       test: function(sqlite3){
         warn("The vtab/module JS bindings are experimental and subject to change.");
-        const vth = sqlite3.VtabHelper;
+        const VT = sqlite3.vtab;
         const tmplCols = Object.assign(Object.create(null),{
           A: 0, B: 1
         });
@@ -1926,8 +1909,8 @@ self.sqlite3InitModule = sqlite3InitModule;
                 pDb, "CREATE TABLE ignored(a,b)"
               );
               if(0===rc){
-                const t = vth.xVtab.create(ppVtab);
-                T.assert(t === vth.xVtab.get(wasm.getPtrValue(ppVtab)));
+                const t = VT.xVtab.create(ppVtab);
+                T.assert(t === VT.xVtab.get(wasm.getPtrValue(ppVtab)));
                 vtabTrace("xCreate",...arguments," ppVtab =",t.pointer);
               }
               return rc;
@@ -1935,12 +1918,12 @@ self.sqlite3InitModule = sqlite3InitModule;
             xConnect: true,
             xDestroy: function(pVtab){
               vtabTrace("xDestroy/xDisconnect",pVtab);
-              vth.xVtab.dispose(pVtab);
+              VT.xVtab.dispose(pVtab);
             },
             xDisconnect: true,
             xOpen: function(pVtab, ppCursor){
-              const t = vth.xVtab.get(pVtab),
-                    c = vth.xCursor.create(ppCursor);
+              const t = VT.xVtab.get(pVtab),
+                    c = VT.xCursor.create(ppCursor);
               T.assert(t instanceof capi.sqlite3_vtab)
                 .assert(c instanceof capi.sqlite3_vtab_cursor);
               vtabTrace("xOpen",...arguments," cursor =",c.pointer);
@@ -1948,19 +1931,19 @@ self.sqlite3InitModule = sqlite3InitModule;
             },
             xClose: function(pCursor){
               vtabTrace("xClose",...arguments);
-              const c = vth.xCursor.unget(pCursor);
+              const c = VT.xCursor.unget(pCursor);
               T.assert(c instanceof capi.sqlite3_vtab_cursor)
-                .assert(!vth.xCursor.get(pCursor));
+                .assert(!VT.xCursor.get(pCursor));
               c.dispose();
             },
             xNext: function(pCursor){
               vtabTrace("xNext",...arguments);
-              const c = vth.xCursor.get(pCursor);
+              const c = VT.xCursor.get(pCursor);
               ++c._rowId;
             },
             xColumn: function(pCursor, pCtx, iCol){
               vtabTrace("xColumn",...arguments);
-              const c = vth.xCursor.get(pCursor);
+              const c = VT.xCursor.get(pCursor);
               switch(iCol){
                   case tmplCols.A:
                     capi.sqlite3_result_int(pCtx, 1000 + c._rowId);
@@ -1973,34 +1956,33 @@ self.sqlite3InitModule = sqlite3InitModule;
             },
             xRowid: function(pCursor, ppRowid64){
               vtabTrace("xRowid",...arguments);
-              const c = vth.xCursor.get(pCursor);
-              vth.xRowid(ppRowid64, c._rowId);
+              const c = VT.xCursor.get(pCursor);
+              VT.xRowid(ppRowid64, c._rowId);
             },
             xEof: function(pCursor){
               vtabTrace("xEof",...arguments);
-              return vth.xCursor.get(pCursor)._rowId>=10;
+              return VT.xCursor.get(pCursor)._rowId>=10;
             },
             xFilter: function(pCursor, idxNum, idxCStr,
                               argc, argv/* [sqlite3_value* ...] */){
               vtabTrace("xFilter",...arguments);
-              const c = vth.xCursor.get(pCursor);
+              const c = VT.xCursor.get(pCursor);
               c._rowId = 0;
-              const list = vth.sqlite3ValuesToJs(argc, argv);
+              const list = VT.sqlite3ValuesToJs(argc, argv);
               T.assert(argc === list.length);
             },
             xBestIndex: function(pVtab, pIdxInfo){
               vtabTrace("xBestIndex",...arguments);
-              //const t = vth.xVtab.get(pVtab);
-              const pii = vth.xIndexInfo(pIdxInfo);
+              //const t = VT.xVtab.get(pVtab);
+              const pii = VT.xIndexInfo(pIdxInfo);
               pii.$estimatedRows = 10;
               pii.$estimatedCost = 10.0;
               pii.dispose();
             }
           }/*methods*/
         };
-        const tmplMod = vth.setupModule(modConfig);
-        T.assert(tmplMod instanceof capi.sqlite3_module)
-          .assert(1===tmplMod.$iVersion);
+        const tmplMod = VT.setupModule(modConfig);
+        T.assert(1===tmplMod.$iVersion);
         this.db.onclose.disposeAfter.push(tmplMod);
         this.db.checkRc(capi.sqlite3_create_module(
           this.db.pointer, modConfig.name, tmplMod.pointer, 0
index 571bb34a7255fea6421a333479dbe3451b427efe..17706e085e2f9ac1832699e8475a7ae7ca2f59f8 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Support\s".scanstats\sest"\sto\senable\sincluding\splanner\sestimates\sin\squery\sprofiles.
-D 2022-12-08T21:05:33.635
+C Reorganization\sand\srenaming\sin\sthe\snew\sVFS/vtab\sJS\spieces.
+D 2022-12-09T00:50:39.739
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -509,8 +509,8 @@ F ext/wasm/api/sqlite3-api-prologue.js 1380e933325c11786b2afc93fc8ff88c2fd1ffeac
 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f
 F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
 F ext/wasm/api/sqlite3-opfs-async-proxy.js 7795b84b66a7a8dedc791340709b310bb497c3c72a80bef364fa2a58e2ddae3f
-F ext/wasm/api/sqlite3-v-helper.js 3f0ef738f5c44943f05ec5bd86976d617e8ae229a0127a1efe81bbb4763293a7
-F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 8ec510fee735c646fb18a3b99f0ca5ca461f9e066c43cdc404d7144f12ae6ed6
+F ext/wasm/api/sqlite3-v-helper.js edcf2dd0caab42aeac41e41e3e97a36d1ada4eb2fdd02cda4488c5b9f9144e0b
+F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 78133d710bee4c48a1a30262b44a284bc017a3751caa7967bdc030f5d0178daa
 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
 F ext/wasm/api/sqlite3-wasm.c 97034ab4f40ec1fac71ccfaf3afffdca6b1ea2dcd95b7871527bad0f34e152b0
 F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b
@@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
 F ext/wasm/test-opfs-vfs.js 44363db07b2a20e73b0eb1808de4400ca71b703af718d0fa6d962f15e73bf2ac
 F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9
 F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406
-F ext/wasm/tester1.c-pp.js ff147d87a1b6b827484da0bedf6f9f03ae027d6d4aec8ab9b22b22801c6df474
+F ext/wasm/tester1.c-pp.js 6be7c89efbf4110ca55475755e14d23b34d7ca835f4775552e02ef47bac0a648
 F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70
 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
 F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
@@ -2067,8 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P c31e7488ac1a6b957782b72bd026b1f0590637b631e44a1fdf1dedeb5c587819
-R 196dc006e445c45f419d571c91fca0d9
-U dan
-Z b6f422040c9b3b9b458fdf6204a182d0
+P 0fe71287c953bd813a34ba383f5debd4d1fc8bf3c74e1e27adacec0d6e207ded
+R 0f31cb3eb615ba1b41f313a7cb7afe85
+U stephan
+Z 3328c6b1aad7d12dae010d17db3f3e30
 # Remove this line to create a well-formed Fossil manifest.
index 6ab5406dfae33db90978b55a30590e786c135963..af2aada558e908c293d023fc9ce0d39ff30c3ffe 100644 (file)
@@ -1 +1 @@
-0fe71287c953bd813a34ba383f5debd4d1fc8bf3c74e1e27adacec0d6e207ded
\ No newline at end of file
+1c2dda177a11fcc5b66e5554507c23ba4b9948a710b3bccfb26963b9851d40a4
\ No newline at end of file