]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
More infrastructure towards binding FTS5 customization support to WASM.
authorstephan <stephan@noemail.net>
Thu, 3 Aug 2023 16:21:24 +0000 (16:21 +0000)
committerstephan <stephan@noemail.net>
Thu, 3 Aug 2023 16:21:24 +0000 (16:21 +0000)
FossilOrigin-Name: 163e3e44b16caa7ceb2805d29a76d8975e66fe429a911995b1c2f8429b080645

ext/wasm/GNUmakefile
ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-fts5 [new file with mode: 0644]
ext/wasm/api/sqlite3-api-cleanup.js
ext/wasm/api/sqlite3-api-glue.js
ext/wasm/api/sqlite3-fts5-helper.js [new file with mode: 0644]
ext/wasm/api/sqlite3-v-helper.js
ext/wasm/api/sqlite3-wasm.c
ext/wasm/common/whwasmutil.js
ext/wasm/tester1.c-pp.js
manifest
manifest.uuid

index 3cd1d930afa8a4d83c76e74667b15fd2229e083f..5c18e4f9554b4c3bc8dbb74e43e91123fa089e57 100644 (file)
@@ -349,6 +349,12 @@ EXPORTED_FUNCTIONS.api.in := $(EXPORTED_FUNCTIONS.api.main)
 ifeq (1,$(SQLITE_C_IS_SEE))
   EXPORTED_FUNCTIONS.api.in += $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-see)
 endif
+ifeq (1,$(emcc.WASM_BIGINT))
+  ifneq (,$(filter -DSQLITE_ENABLE_FTS5,$(SQLITE_OPT)))
+    EXPORTED_FUNCTIONS.api.in += $(abspath $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-fts5)
+  endif
+endif
+
 EXPORTED_FUNCTIONS.api := $(dir.tmp)/EXPORTED_FUNCTIONS.api
 $(EXPORTED_FUNCTIONS.api): $(EXPORTED_FUNCTIONS.api.in) $(sqlite3.c) $(MAKEFILE)
        cat $(EXPORTED_FUNCTIONS.api.in) > $@
@@ -375,6 +381,9 @@ sqlite3-api.jses += $(dir.api)/sqlite3-api-worker1.js
 sqlite3-api.jses += $(dir.api)/sqlite3-v-helper.js
 sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs.c-pp.js
 sqlite3-api.jses += $(dir.api)/sqlite3-vfs-opfs-sahpool.c-pp.js
+ifneq (,$(filter -DSQLITE_ENABLE_FTS5,$(SQLITE_OPT)))
+  sqlite3-api.jses += $(dir.api)/sqlite3-fts5-helper.js
+endif
 sqlite3-api.jses += $(dir.api)/sqlite3-api-cleanup.js
 
 # SOAP.js is an external API file which is part of our distribution
diff --git a/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-fts5 b/ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-fts5
new file mode 100644 (file)
index 0000000..0141abf
--- /dev/null
@@ -0,0 +1 @@
+_fts5_api_from_db
index 65dbb4eb64c98ccc4478e95368afdcd4fd323300..dbea99c6133903dd353967687628729d9274131c 100644 (file)
@@ -52,9 +52,10 @@ if('undefined' !== typeof Module){ // presumably an Emscripten build
     delete globalThis.sqlite3ApiBootstrap;
     delete globalThis.sqlite3ApiConfig;
   }
-
+  delete sqlite3.__dbCleanupMap;
   Module.sqlite3 = sqlite3 /* Needed for customized sqlite3InitModule() to be able to
                               pass the sqlite3 object off to the client. */;
+  sqlite3.wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
 }else{
   console.warn("This is not running in an Emscripten module context, so",
                "globalThis.sqlite3ApiBootstrap() is _not_ being called due to lack",
index fcfccb553a2e7334c67e68ee0e63eb152cdd58c1..7f05d374430343ed97faf161e9124914091d10f5 100644 (file)
@@ -261,6 +261,18 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
       }),
       "*"/*pUserData*/
     ]],
+    /**
+       Achtung: when specifying an xDestroy() method via
+       sqlite3_set_auxdata(), it is up to the client to re-set it to
+       0/NULL at the end of its lifetime (e.g. in the associated UDF's
+       xFinal() impl), The C library will be able to call the
+       destructor but _not_ uninstall the temporary WASM-bound proxy
+       function because it does not have enough information to do
+       so. Alternately, clients may create the function pointer
+       themselves using wasm.createFunction() and pass that pointer
+       here, in which case they avoid creating a stranded "temporary"
+       function binding.
+    */
     ["sqlite3_set_auxdata", undefined, [
       "sqlite3_context*", "int", "*",
       new wasm.xWrap.FuncPtrAdapter({
@@ -421,8 +433,6 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
 
   // Add session/changeset APIs...
   if(wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add){
-    /* ACHTUNG: 2022-12-23: the session/changeset API bindings are
-       COMPLETELY UNTESTED. */
     /**
        FuncPtrAdapter options for session-related callbacks with the
        native signature "i(ps)". This proxy converts the 2nd argument
@@ -597,6 +607,12 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     ]);
   }/*session/changeset APIs*/
 
+  if(wasm.bigIntEnabled && !!wasm.exports.fts5_api_from_db){
+    wasm.bindingSignatures.int64.push(
+      ['fts5_api_from_db', 'fts5_api*', 'sqlite3*']
+    );
+  }/* fts5 APIs */
+
   /**
      Functions which are intended solely for API-internal use by the
      WASM components, not client code. These get installed into
@@ -659,8 +675,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
       function(v){
         if(wasm.isPtr(v)) return v;
         v = ''+v;
-        let rc = this[v];
-        return rc || (this[v] = wasm.allocCString(v));
+        const rc = this[v];
+        return (undefined===rc) ? (this[v] = wasm.allocCString(v)) : rc;
       }.bind(Object.create(null))
     );
 
@@ -717,7 +733,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     });
 
     const __xRcPtr = wasm.xWrap.resultAdapter('*');
-    wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr)
+    wasm.xWrap.resultAdapter
+    ('fts5_api*', __xRcPtr)
+    ('sqlite3*', __xRcPtr)
     ('sqlite3_context*', __xRcPtr)
     ('sqlite3_stmt*', __xRcPtr)
     ('sqlite3_value*', __xRcPtr)
@@ -909,9 +927,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      UDFs and collations so that sqlite3_close_v2() can clean up any
      automated JS-to-WASM function conversions installed by those.
   */
-  const __argPDb = (pDb)=>wasm.xWrap.argAdapter('sqlite3*')(pDb);
+  const __argPDb = wasm.xWrap.argAdapter('sqlite3*');
   const __argStr = (str)=>wasm.isPtr(str) ? wasm.cstrToJs(str) : str;
-  const __dbCleanupMap = function(
+  const __dbCleanupMap = sqlite3.__dbCleanupMap = function(
     pDb, mode/*0=remove, >0=create if needed, <0=do not create if missing*/
   ){
     pDb = __argPDb(pDb);
@@ -976,6 +994,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
   */
   __dbCleanupMap.cleanup = function(pDb){
     pDb = __argPDb(pDb);
+    //console.warn("db cleanup",pDb);
     //wasm.xWrap.FuncPtrAdapter.debugFuncInstall = false;
     /**
        Installing NULL functions in the C API will remove those
@@ -1004,6 +1023,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
         console.warn("close-time call of",name+"(",closeArgs,") threw:",e);
       }
     }
+    for(const callback of __dbCleanupMap.extraCallbacks){
+      callback(pDb);
+    }
     const m = __dbCleanupMap(pDb, 0);
     if(!m) return;
     if(m.collation){
@@ -1040,6 +1062,13 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     delete m.udf;
     delete m.wudf;
   }/*__dbCleanupMap.cleanup()*/;
+  /**
+     Downstream code, namely sqlite3-fts5-helper.js, should add any custom
+     cleanup handlers to __dbCleanupMap.extraCallbacks. Each function in this
+     array will be called during sqlite3_close_v2() and passed a pointer to
+     the being-destroyed (sqlite3*) object.
+  */
+  __dbCleanupMap.extraCallbacks = [];
 
   {/* Binding of sqlite3_close_v2() */
     const __sqlite3CloseV2 = wasm.xWrap("sqlite3_close_v2", "int", "sqlite3*");
@@ -1157,6 +1186,9 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     /**
        JS proxies for the various sqlite3_create[_window]_function()
        callbacks, structured in a form usable by wasm.xWrap.FuncPtrAdapter.
+
+       TODO: explore an API option which more closely resembles the
+       /ext/jni mapping, which is much friendlier at the client level.
     */
     const __cfProxy = Object.assign(Object.create(null), {
       xInverseAndStep: {
@@ -1668,5 +1700,4 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     }
   }/*pKvvfs*/
 
-  wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
 });
diff --git a/ext/wasm/api/sqlite3-fts5-helper.js b/ext/wasm/api/sqlite3-fts5-helper.js
new file mode 100644 (file)
index 0000000..061b7ca
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+** 2023-08-03
+**
+** The author disclaims copyright to this source code.  In place of a
+** legal notice, here is a blessing:
+**
+** *   May you do good and not evil.
+** *   May you find forgiveness for yourself and forgive others.
+** *   May you share freely, never taking more than you give.
+*/
+
+/**
+   This file installs sqlite3.fts5, a namespace which exists to assist
+   in JavaScript-side extension of FTS5.
+*/
+'use strict';
+globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+  const wasm = sqlite3.wasm, capi = sqlite3.capi, toss = sqlite3.util.toss3;
+  const __dbCleanupMap = sqlite3.__dbCleanupMap
+        || toss("Maintenance needed: can't reach sqlite3.__dbCleanupMap.");
+  if(!capi.fts5_api_from_db){
+    return /*this build does not have FTS5*/;
+  }
+  const fts = sqlite3.fts5 = Object.create(null);
+  /**
+     Move FTS-specific APIs from sqlite3.capi to sqlite3.fts.
+  */
+  for(const c of [
+    'Fts5ExtensionApi', 'Fts5PhraseIter', 'fts5_api',
+    'fts5_api_from_db'
+  ]){
+    fts[c] = capi[c] || toss("Cannot find capi."+c);
+    delete capi[c];
+  }
+
+  const cache = Object.create(null);
+
+  const xFunctionArgAdapter = new wasm.xWrap.FuncPtrAdapter({
+    name: 'fts5_api::xCreateFunction(xFunction)',
+    signature: 'v(pppip)',
+    contextKey: (argv,argIndex)=>{
+      return (argv[0]/*(fts5_api*)*/
+              + wasm.cstrToJs(argv[1]).toLowerCase()/*name*/)
+    },
+    callProxy: (callback)=>{
+      return (pFtsXApi, pFtsCx, pCtx, argc, pArgv)=>{
+        try{
+          capi.sqlite3_result_js(pCtx, callback(
+            pFtsXApi, pFtsCx, pCtx,
+            capi.sqlite3_values_to_js(argc, pArgv)
+          ));
+        }catch(e){
+          capi.sqlite3_result_error_js(pCtx, e);
+        }
+      }
+    }
+  });
+
+  const xDestroyArgAdapter = new wasm.xWrap.FuncPtrAdapter({
+    name: 'fts5_api::xCreateFunction(xDestroy)',
+    signature: 'v(p)',
+    contextKey: xFunctionArgAdapter.contextKey,
+    callProxy: (callback)=>{
+      return (pArg)=>{
+        try{ callback(pArg) }
+        catch(e){
+          sqlite3.config.warn("FTS5 function xDestroy() threw. Ignoring.",e);
+        }
+      }
+    }
+  });
+
+  /**
+     Arrange for WASM functions dynamically created via this API to be
+     uninstalled when the db they were installed for is closed... */
+  const __fts5FuncsPerDb = Object.create(null);
+  const __cleanupForDb = function(pDb){
+    return (__fts5FuncsPerDb[pDb] || (__fts5FuncsPerDb[pDb] = new Set));
+  };
+  __dbCleanupMap._addFts5Function = function ff(pDb, name){
+    __cleanupForDb(pDb).add(name.toLowerCase());
+  };
+  __dbCleanupMap.extraCallbacks.push(function(pDb){
+    const list = __fts5FuncsPerDb[pDb];
+    if(list){
+      const fapi = fts.fts5_api_from_db(pDb)
+      const sfapi = new fts.fts5_api(fapi);
+      const scope = wasm.scopedAllocPush();
+      //wasm.xWrap.FuncPtrAdapter.debugFuncInstall = true;
+      try{
+        const xCF = wasm.functionEntry(sfapi.$xCreateFunction);
+        for(const name of list){
+          //sqlite3.config.warn("Clearing FTS function",pDb,name);
+          try{
+            const zName = wasm.scopedAllocCString(name);
+            /* In order to clean up properly we first have to invoke
+               the low-level (unwrapped) sfapi.$xCreateFunction and
+               then fake some calls into the Function-to-funcptr
+               apapters. If we just call cache.xcf(...) then the
+               adapter ends up uninstalling the xDestroy pointer which
+               sfapi.$xCreateFunction is about to invoke, leading to
+               an invalid memory access. */
+            xCF(fapi, zName, 0, 0, 0);
+            // Now clean up our FuncPtrAdapters in a round-about way...
+            const argv = [fapi, zName, 0, 0, 0];
+            xFunctionArgAdapter.convertArg(argv[3], argv, 3);
+            // xDestroyArgAdapter leads to an invalid memory access
+            // for as-yet-unknown reasons. For the time being we're
+            // leaking these.
+            //xDestroyArgAdapter.convertArg(argv[4], argv, 4);
+          }catch(e){
+            sqlite3.config.error("Error removing FTS func",name,e);
+          }
+        }
+      }finally{
+        sfapi.dispose();
+        delete __fts5FuncsPerDb[pDb];
+        wasm.scopedAllocPop(scope);
+      }
+      //wasm.xWrap.FuncPtrAdapter.debugFuncInstall = false;
+    }
+  });
+
+  const xArgDb = wasm.xWrap.argAdapter('sqlite3*');
+
+  /**
+     Convenience wrapper to fts5_api::xCreateFunction.
+
+     Creates a new FTS5 function for the given database. The arguments are:
+
+     - db must be either an sqlite3.oo1.DB instance or a WASM pointer
+       to (sqlite3*).
+
+     - name: name (JS string) of the function
+
+     - xFunction either a Function or a pointer to a WASM function. In
+       the former case a WASM-bound wrapper for the function gets
+       installed for the life of the given db handle. The function
+       must return void and accept args in the form
+       (ptrToFts5ExtensionApi, ptrToFts5Context, ptrToSqlite3Context,
+       array-of-values).
+
+     - xDestroy optional Function or pointer to WASM function to call
+       when the binding is destroyed (when the db handle is
+       closed). The function will, in this context, always be passed 0
+       as its only argument. A passed-in function must, however,
+       have one argument so that type signature checks will pass.
+
+     The 2nd and subsequent aruguments may optionally be packed into
+     a single Object with like-named properties.
+
+     The callback functions may optionally be provided in the form of
+     a single object with xFunction and xDestroy properties.
+
+     This function throws on error, of which there are many potential
+     candidates. It returns `undefined`.
+  */
+  fts.createFunction = function(db, name, xFunction, xDestroy = 0){
+    db = xArgDb(db);
+    if(!wasm.isPtr(db)) toss("Invalid db argument.");
+    if( 2 === arguments.length && 'string' !== typeof name){
+      xDestroy = name.xDestroy || null;
+      xFunction = name.xFunction || null;
+      name = name.name;
+    }
+    if( !name || 'string' !== typeof name ) toss("Invalid name argument.");
+    const fapi = fts.fts5_api_from_db(db)
+          || toss("Internal error - cannot get FTS5 API object for db.");
+    const sfapi = new fts.fts5_api(fapi);
+    try{
+      const xcf = cache.xcf || (
+        cache.xcf = wasm.xWrap(sfapi.$xCreateFunction,'int',[
+          '*', 'string', '*', xFunctionArgAdapter, xDestroyArgAdapter
+        ])
+      )/* this cache entry is only legal as long as nobody replaces
+          the xCreateFunction() method */;
+      const rc = xcf(fapi, name, 0, xFunction || 0, xDestroy || 0 );
+      if(rc) toss(rc,"FTS5::xCreateFunction() failed.");
+      __dbCleanupMap._addFts5Function(db, name);
+    }finally{
+      sfapi.dispose();
+    }
+  };
+
+}/*sqlite3ApiBootstrap.initializers.push()*/);
index e63da8afc305323f75fc1ffedbc510227f827636..a55660d3d3a2917ac36f6f52a9f269aea31f9e53 100644 (file)
@@ -10,7 +10,7 @@
 */
 
 /**
-   This file installs sqlite3.vfs, and object which exists to assist
+   This file installs sqlite3.vfs, an object which exists to assist
    in the creation of JavaScript implementations of sqlite3_vfs, along
    with its virtual table counterpart, sqlite3.vtab.
 */
index e7e7fedb3b007ef0c51852dbffaf7f9bdfa94c9c..a2dda0ca177a9a933499afb3f100486b1227952d 100644 (file)
@@ -363,6 +363,27 @@ int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
   return err_code;
 }
 
+#ifdef SQLITE_ENABLE_FTS5
+/*
+** Return a pointer to the fts5_api pointer for database connection db.
+** If an error occurs, return NULL and leave an error in the database
+** handle (accessible using sqlite3_errcode()/errmsg()).
+**
+** This function was taken verbatim from the /fts5.html docs.
+*/
+SQLITE_WASM_EXPORT
+fts5_api *fts5_api_from_db(sqlite3 *db){
+  fts5_api *pRet = 0;
+  sqlite3_stmt *pStmt = 0;
+  if( SQLITE_OK==sqlite3_prepare(db, "SELECT fts5(?1)", -1, &pStmt, 0) ){
+    sqlite3_bind_pointer(pStmt, 1, (void*)&pRet, "fts5_api_ptr", NULL);
+    sqlite3_step(pStmt);
+  }
+  sqlite3_finalize(pStmt);
+  return pRet;
+}
+#endif /*SQLITE_ENABLE_FTS5*/
+
 #if SQLITE_WASM_TESTS
 struct WasmTestStruct {
   int v4;
index ee7ea20c3406242859a65f97db742bbe87dd9bae..4b0a78582ffddff9260588ecafd59ff83b360442 100644 (file)
@@ -1384,15 +1384,19 @@ globalThis.WhWasmUtilInstaller = function(target){
      conversion of argument or return types, but see xWrap() and
      xCallWrapped() for variants which do.
 
+     If the first argument is a function is is assumed to be
+     a WASM-bound function and is used as-is instead of looking up
+     the function via xGet().
+
      As a special case, if passed only 1 argument after the name and
      that argument in an Array, that array's entries become the
      function arguments. (This is not an ambiguous case because it's
      not legal to pass an Array object to a WASM function.)
   */
   target.xCall = function(fname, ...args){
-    const f = target.xGet(fname);
+    const f = (fname instanceof Function) ? fname : target.xGet(fname);
     if(!(f instanceof Function)) toss("Exported symbol",fname,"is not a function.");
-    if(f.length!==args.length) __argcMismatch(fname,f.length)
+    if(f.length!==args.length) __argcMismatch(((f===fname) ? f.name : fname),f.length)
     /* This is arguably over-pedantic but we want to help clients keep
        from shooting themselves in the foot when calling C APIs. */;
     return (2===arguments.length && Array.isArray(arguments[1]))
@@ -1539,7 +1543,7 @@ globalThis.WhWasmUtilInstaller = function(target){
        jsFuncToWasm().
 
      - bindScope (string): one of ('transient', 'context',
-       'singleton'). Bind scopes are:
+       'singleton', 'permanent'). Bind scopes are:
 
        - 'transient': it will convert JS functions to WASM only for
          the duration of the xWrap()'d function call, using
@@ -1774,11 +1778,29 @@ globalThis.WhWasmUtilInstaller = function(target){
   const __xResultAdapterCheck =
         (t)=>xResult.get(t) || toss("Result adapter not found:",t);
 
+  /**
+     Fetches the xWrap() argument adapter mapped to t, calls it,
+     passing in all remaining arguments, and returns the result.
+     Throws if t is not mapped to an argument converter.
+  */
   cache.xWrap.convertArg = (t,...args)=>__xArgAdapterCheck(t)(...args);
+  /**
+     Identical to convertArg() except that it does not perform
+     an is-defined check on the mapping to t before invoking it.
+  */
   cache.xWrap.convertArgNoCheck = (t,...args)=>xArg.get(t)(...args);
 
+  /**
+     Fetches the xWrap() result adapter mapped to t, calls it, passing
+     it v, and returns the result.  Throws if t is not mapped to an
+     argument converter.
+  */
   cache.xWrap.convertResult =
     (t,v)=>(null===t ? v : (t ? __xResultAdapterCheck(t)(v) : undefined));
+  /**
+     Identical to convertResult() except that it does not perform an
+     is-defined check on the mapping to t before invoking it.
+  */
   cache.xWrap.convertResultNoCheck =
     (t,v)=>(null===t ? v : (t ? xResult.get(t)(v) : undefined));
 
index c1b16d5e81be85a0415dc7d112b875d264adc713..1e83d7e7c0735d864564b027ef5d2455c3fe9288 100644 (file)
@@ -2899,6 +2899,56 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
       }
     })/*session API sanity tests*/
   ;/*end of session API group*/;
+  ////////////////////////////////////////////////////////////////////////
+  T.g('FTS5')
+    .t({
+      name: "Sanity checks",
+      predicate: (sqlite3)=>sqlite3.fts5 || "Missing sqlite3.fts5 namespace.",
+      test: function(sqlite3){
+        const db = new sqlite3.oo1.DB();
+        db.exec([
+          "create virtual table ft using fts5(a,b);",
+          "insert into ft(a,b) values",
+          "('a1','b1'),",
+          "('a2','b2'),",
+          "('a3','b3');"
+        ]);
+        const fts = sqlite3.fts5;
+        let pApi = fts.fts5_api_from_db(db);
+        T.assert( !!pApi );
+        let fApi = new fts.fts5_api(pApi);
+        T.assert( fApi.$iVersion >= 2 );
+        fApi.dispose();
+        fApi = undefined;
+        let destroyCalled = false;
+        fts.createFunction(db,{
+          name: 'mymatch',
+          xFunction: function(pFtsX, pFtsCx, pCtx, argv){
+            //log("mymatch!", argv.length, argv);
+            // Both of these return-value approaches are equivalent:
+            if(0){
+              return "MY+"+argv.join(':');
+            }else{
+              capi.sqlite3_result_text(pCtx, "MY+"+argv.join(':'), -1, 0);
+              // implicit return of undefined
+            }
+          },
+          xDestroy: function(){
+            destroyCalled = true;
+          }
+        });
+        let list = db.selectValues(
+          "select mymatch(ft,a,b) from ft where b match 'b2'"
+          //^^^ results in a "no such cursor: 0" error
+          //"select a from ft where b match 'b2'"
+        );
+        T.assert( 1 === list.length )
+          .assert( 'MY+a2:b2' === list[0] );
+        db.close();
+        T.assert( destroyCalled );
+        //toss("Testing");
+      }
+    })/*FTS5*/
 
   ////////////////////////////////////////////////////////////////////////
   T.g('OPFS: Origin-Private File System',
index 7dc9860aa350d5dc07220a1bbeb8455ff519bfeb..f1cc885586fc5f002abee6a96c782fe0dba6f9b5 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\sdiscrepancy\sbetween\ssqlite3_values_to_js()\sand\sits\sAPI\sdocs/intended\sbehavior.
-D 2023-08-03T16:02:30.143
+C More\sinfrastructure\stowards\sbinding\sFTS5\scustomization\ssupport\sto\sWASM.
+D 2023-08-03T16:21:24.022
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -487,10 +487,11 @@ F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
 F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
 F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
-F ext/wasm/GNUmakefile ddf1aede4275e404c7eda782462c33b6406fcd2dd327241f6b22c0f7b80938e4
+F ext/wasm/GNUmakefile a33d4acc4fab03bd4a1c76243ec1e43abaeb6e6e29f0971444bcb008ec6420ec
 F ext/wasm/README-dist.txt 6382cb9548076fca472fb3330bbdba3a55c1ea0b180ff9253f084f07ff383576
 F ext/wasm/README.md a8a2962c3aebdf8d2104a9102e336c5554e78fc6072746e5daf9c61514e7d193
 F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api d6a5078f48a5301ed17b9a30331075d9b2506e1360c1f0dee0c7816c10acd9ab
+F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-fts5 abdb0216e3035d48f797302f8712dd31d917b4dd7dfdb7957428f8046ebaf1b1
 F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
 F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
 F ext/wasm/api/README.md 5eb44fa02e9c693a1884a3692428647894b0380b24bca120866b7a24c8786134
@@ -499,17 +500,18 @@ F ext/wasm/api/extern-pre-js.js cc61c09c7a24a07dbecb4c352453c3985170cec12b4e7e7e
 F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08902f15c34720ee4a1
 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62
 F ext/wasm/api/pre-js.c-pp.js ad906703f7429590f2fbf5e6498513bf727a1a4f0ebfa057afb08161d7511219
-F ext/wasm/api/sqlite3-api-cleanup.js d235ad237df6954145404305040991c72ef8b1881715d2a650dda7b3c2576d0e
-F ext/wasm/api/sqlite3-api-glue.js 8d087ebb00d1db2afa393b9ea7bfe1ec1fd7387c566d9bb160119e66dd8c2d04
+F ext/wasm/api/sqlite3-api-cleanup.js 8489ac9933783f36807cfa5d79bfa366008c0443b42bf47bdef41bbfce4aa367
+F ext/wasm/api/sqlite3-api-glue.js c8fee0a75cf655bb830f01b6d0a53e3648a46be71d69256b2853c085004bf89e
 F ext/wasm/api/sqlite3-api-oo1.js 9678dc4d9a5d39632b6ffe6ea94a023119260815bf32f265bf5f6c36c9516db8
 F ext/wasm/api/sqlite3-api-prologue.js 76258e160bf6a89cc75a7d3c05646a054c8cab7219cd1e10bc20cacaad022131
 F ext/wasm/api/sqlite3-api-worker1.js 9f32af64df1a031071912eea7a201557fe39b1738645c0134562bb84e88e2fec
+F ext/wasm/api/sqlite3-fts5-helper.js fd9a0cad447a56734b134eab57a832be8820e8cfb8a672c0b1b54c3805485c2e
 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
 F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
-F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25
+F ext/wasm/api/sqlite3-v-helper.js 8dc3da6e69d51f455b64cc88fec7977f528d79ec267cfcdd97b606c8cc4cd156
 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 54cee22aacadb9dfaea438d72ac0882249d028c37903208d48c52871290ceff7
 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js e7a690e0e78ff4d563f2eca468f91db69f001ff4b79c6d2304cbb6f62dca437d
-F ext/wasm/api/sqlite3-wasm.c 2ef539a238a81d339ff0cec9dc1d8dc62402f3a9a1e7b72ebd130737a1590d17
+F ext/wasm/api/sqlite3-wasm.c 45d2ce0089f1a41123fb88998c6f55be8d6cc2fdde8f861a5181a93f4ba57a97
 F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f
 F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75
 F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
@@ -518,7 +520,7 @@ F ext/wasm/c-pp.c 6d80d8569d85713effe8b0818a3cf51dc779e3f0bf8dc88771b8998552ee25
 F ext/wasm/common/SqliteTestUtil.js 7adaeffef757d8708418dc9190f72df22367b531831775804b31598b44f6aa51
 F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
 F ext/wasm/common/testing.css e97549bab24126c24e0daabfe2de9bb478fb0a69fdb2ddd0a73a992c091aad6f
-F ext/wasm/common/whwasmutil.js db6368ee57af90ee6691b6fb3ca97ee8064d12482e06a29113127c67b08f956e
+F ext/wasm/common/whwasmutil.js 1dcce8bc4f90cdc80f1bc0256b44b24f043301968d9ed7cdcd32a16e87babe00
 F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
 F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
 F ext/wasm/demo-123.js 38aa8faec4d0ace1c973bc8a7a1533584463ebeecd4c420daa7d9687beeb9cb5
@@ -554,7 +556,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
 F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b
 F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
 F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
-F ext/wasm/tester1.c-pp.js b88dcad5424a652e8204c44a71bbc3deb22a4922c97ba792aedbabb7a6827b91
+F ext/wasm/tester1.c-pp.js b1200f52a1b2ab51c0a2bc6be811090ee0a71e0d9661fcfe540073b80fb4d607
 F ext/wasm/tests/opfs/concurrency/index.html 0802373d57034d51835ff6041cda438c7a982deea6079efd98098d3e42fbcbc1
 F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
 F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
@@ -2049,8 +2051,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 52c8b73ae3095b7e9f4d5440169c818677e484d85195036a0d82db0d04a428e5
-R f66e2e5bbfcc0156634777fa6a1a3cf0
+P 16658b3c64d7f9690b097d999a8fbdc49dedf484f72174059718a768f61e875b
+R b3278d833ca5b1cc70c3ac9bdfedd32f
 U stephan
-Z 6955fafa5414b6323f1535856f263b13
+Z 9a202e887806dd7f5eca1a911834ce23
 # Remove this line to create a well-formed Fossil manifest.
index f413a0221ec2a838a80d1fe0edfc1fefbe085d8a..df88a92142fd266cb09e4f376a6512949bfe6d27 100644 (file)
@@ -1 +1 @@
-16658b3c64d7f9690b097d999a8fbdc49dedf484f72174059718a768f61e875b
\ No newline at end of file
+163e3e44b16caa7ceb2805d29a76d8975e66fe429a911995b1c2f8429b080645
\ No newline at end of file