]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Initial infrastructure for adding virtual table/table-valued function support to...
authorstephan <stephan@noemail.net>
Mon, 5 Dec 2022 05:30:03 +0000 (05:30 +0000)
committerstephan <stephan@noemail.net>
Mon, 5 Dec 2022 05:30:03 +0000 (05:30 +0000)
FossilOrigin-Name: c202d7a0398b9aabc2babba5c4c91a313f32bbf37549d419775642bb4aa3936a

ext/wasm/api/sqlite3-api-glue.js
ext/wasm/api/sqlite3-wasm.c
ext/wasm/common/whwasmutil.js
ext/wasm/jaccwabyt/jaccwabyt.js
ext/wasm/jaccwabyt/jaccwabyt.md
manifest
manifest.uuid

index ac1e9fd6d62885cc7b46e54c35efd5633fe02702..eddcfddd1e7f81ccc0a9e139a52ef60ba8557a19 100644 (file)
@@ -603,13 +603,16 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     }
     wasm.ctype = JSON.parse(wasm.cstringToJs(cJson));
     //console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
-    for(const t of ['access', 'blobFinalizers', 'dataTypes',
-                    'encodings', 'fcntl', 'flock', 'ioCap',
-                    'limits',
-                    'openFlags', 'prepareFlags', 'resultCodes',
-                    'serialize', 'syncFlags', 'trace', 'udfFlags',
-                    'version'
-                   ]){
+    const defineGroups = ['access', 'blobFinalizers', 'dataTypes',
+                          'encodings', 'fcntl', 'flock', 'ioCap',
+                          'limits',
+                          'openFlags', 'prepareFlags', 'resultCodes',
+                          'serialize', 'syncFlags', 'trace', 'udfFlags',
+                          'version' ];
+    if(wasm.bigIntEnabled){
+      defineGroups.push('vtab');
+    }
+    for(const t of defineGroups){
       for(const e of Object.entries(wasm.ctype[t])){
         // ^^^ [k,v] there triggers a buggy code transformation via
         // one of the Emscripten-driven optimizers.
@@ -629,19 +632,33 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     capi.sqlite3_js_rc_str = (rc)=>__rcMap[rc];
     /* Bind all registered C-side structs... */
     const notThese = Object.assign(Object.create(null),{
-      // Structs NOT to register
-      WasmTestStruct: true
-    });
-    if(!util.isUIThread()){
+      // For each struct to NOT register, map its name to false:
+      WasmTestStruct: true,
       /* We remove the kvvfs VFS from Worker threads below. */
-      notThese.sqlite3_kvvfs_methods = true;
-    }
+      sqlite3_kvvfs_methods: !util.isUIThread(),
+      sqlite3_index_info: !wasm.bigIntEnabled,
+      sqlite3_index_constraint: !wasm.bigIntEnabled,
+      sqlite3_index_orderby: !wasm.bigIntEnabled,
+      sqlite3_index_constraint_usage: !wasm.bigIntEnabled
+    });
     for(const s of wasm.ctype.structs){
       if(!notThese[s.name]){
         capi[s.name] = sqlite3.StructBinder(s);
       }
     }
-  }/*end C constant imports*/
+    if(capi.sqlite3_index_info){
+      /* Move these inner structs into sqlite3_index_info.  Binding
+      ** them to WASM requires that we create global-scope structs to
+      ** model them with, but those are no longer needed after we've
+      ** passed them to StructBinder. */
+      for(const k of ['sqlite3_index_constraint',
+                      'sqlite3_index_orderby',
+                      'sqlite3_index_constraint_usage']){
+        capi.sqlite3_index_info[k] = capi[k];
+        delete capi[k];
+      }
+    }
+  }/*end C constant and struct imports*/
 
   const pKvvfs = capi.sqlite3_vfs_find("kvvfs");
   if( pKvvfs ){/* kvvfs-specific glue */
@@ -652,8 +669,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
       delete capi.sqlite3_kvvfs_methods;
 
       const kvvfsMakeKey = wasm.exports.sqlite3_wasm_kvvfsMakeKeyOnPstack,
-            pstack = wasm.pstack,
-            pAllocRaw = wasm.exports.sqlite3_wasm_pstack_alloc;
+            pstack = wasm.pstack;
 
       const kvvfsStorage = (zClass)=>
             ((115/*=='s'*/===wasm.getMemValue(zClass))
index f6499243a64da85e7ae2755b1477fe1421664cd1..dc5dff62a7ccecc5a7199d904ecc789ee43eb291 100644 (file)
@@ -368,7 +368,7 @@ void sqlite3_wasm_test_struct(WasmTestStruct * s){
 */
 SQLITE_WASM_KEEP
 const char * sqlite3_wasm_enum_json(void){
-  static char aBuffer[1024 * 12] = {0} /* where the JSON goes */;
+  static char aBuffer[1024 * 16] = {0} /* where the JSON goes */;
   int n = 0, nChildren = 0, nStruct = 0
     /* output counters for figuring out where commas go */;
   char * zPos = &aBuffer[1] /* skip first byte for now to help protect
@@ -410,6 +410,14 @@ const char * sqlite3_wasm_enum_json(void){
     DefInt(SQLITE_ACCESS_READ)/*docs say this is unused*/;
   } _DefGroup;
 
+#if 0
+  /* TODO? Authorizer... */
+  DefGroup(authorizer){
+    DefInt(SQLITE_DENY);
+    DefInt(SQLITE_IGNORE);
+  } _DefGroup;
+#endif
+
   DefGroup(blobFinalizers) {
     /* SQLITE_STATIC/TRANSIENT need to be handled explicitly as
     ** integers to avoid casting-related warnings. */
@@ -681,7 +689,28 @@ const char * sqlite3_wasm_enum_json(void){
     DefStr(SQLITE_VERSION);
     DefStr(SQLITE_SOURCE_ID);
   } _DefGroup;
-  
+
+  DefGroup(vtab) {
+    DefInt(SQLITE_INDEX_SCAN_UNIQUE);
+    DefInt(SQLITE_INDEX_CONSTRAINT_EQ);
+    DefInt(SQLITE_INDEX_CONSTRAINT_GT);
+    DefInt(SQLITE_INDEX_CONSTRAINT_LE);
+    DefInt(SQLITE_INDEX_CONSTRAINT_LT);
+    DefInt(SQLITE_INDEX_CONSTRAINT_GE);
+    DefInt(SQLITE_INDEX_CONSTRAINT_MATCH);
+    DefInt(SQLITE_INDEX_CONSTRAINT_LIKE);
+    DefInt(SQLITE_INDEX_CONSTRAINT_GLOB);
+    DefInt(SQLITE_INDEX_CONSTRAINT_REGEXP);
+    DefInt(SQLITE_INDEX_CONSTRAINT_NE);
+    DefInt(SQLITE_INDEX_CONSTRAINT_ISNOT);
+    DefInt(SQLITE_INDEX_CONSTRAINT_ISNOTNULL);
+    DefInt(SQLITE_INDEX_CONSTRAINT_ISNULL);
+    DefInt(SQLITE_INDEX_CONSTRAINT_IS);
+    DefInt(SQLITE_INDEX_CONSTRAINT_LIMIT);
+    DefInt(SQLITE_INDEX_CONSTRAINT_OFFSET);
+    DefInt(SQLITE_INDEX_CONSTRAINT_FUNCTION);
+  } _DefGroup;
+
 #undef DefGroup
 #undef DefStr
 #undef DefInt
@@ -793,6 +822,137 @@ const char * sqlite3_wasm_enum_json(void){
     } _StructBinder;
 #undef CurrentStruct
 
+
+#define CurrentStruct sqlite3_vtab
+    StructBinder {
+      M(pModule, "p");
+      M(nRef,    "i");
+      M(zErrMsg, "p");
+    } _StructBinder;
+#undef CurrentStruct
+
+#define CurrentStruct sqlite3_vtab_cursor
+    StructBinder {
+      M(pVtab, "p");
+    } _StructBinder;
+#undef CurrentStruct
+
+#define CurrentStruct sqlite3_module
+    StructBinder {
+      M(iVersion,       "i");
+      M(xCreate,        "i(ppippp)");
+      M(xConnect,       "i(ppippp)");
+      M(xBestIndex,     "i(pp)");
+      M(xDisconnect,    "i(p)");
+      M(xDestroy,       "i(p)");
+      M(xOpen,          "i(pp)");
+      M(xClose,         "i(p)");
+      M(xFilter,        "i(pisip)");
+      M(xNext,          "i(p)");
+      M(xEof,           "i(p)");
+      M(xColumn,        "i(ppi)");
+      M(xRowid,         "i(pp)");
+      M(xUpdate,        "i(pipp)");
+      M(xBegin,         "i(p)");
+      M(xSync,          "i(p)");
+      M(xCommit,        "i(p)");
+      M(xRollback,      "i(p)");
+      M(xFindFunction,  "i(pispp)");
+      M(xRename,        "i(ps)");
+      // ^^^ v1. v2+ follows...
+      M(xSavepoint,     "i(pi)");
+      M(xRelease,       "i(pi)");
+      M(xRollbackTo,    "i(pi)");
+      // ^^^ v2. v3+ follows...
+      M(xShadowName,    "i(s)");
+    } _StructBinder;
+#undef CurrentStruct
+    /*
+      module/vtab todos:
+
+      - sqlite3_create_module()
+      - sqlite3_create_module_v2()
+      - sqlite3_drop_modules()
+      - sqlite3_declare_vtab()
+      - sqlite3_overload_function()
+     */
+    
+    /**
+     ** Workaround: in order to map the various inner structs from
+     ** sqlite3_index_info, we have to uplift those into constructs we
+     ** can access by type name. These structs _must_ match their
+     ** in-sqlite3_index_info counterparts byte for byte.
+    */
+    typedef struct {
+      int iColumn;
+      unsigned char op;
+      unsigned char usable;
+      int iTermOffset;
+    } sqlite3_index_constraint;
+    typedef struct {
+      int iColumn;
+      unsigned char desc;
+    } sqlite3_index_orderby;
+    typedef struct {
+      int argvIndex;
+      unsigned char omit;
+    } sqlite3_index_constraint_usage;
+    { /* Validate that the above struct sizeof()s match
+      ** expectations. We could improve upon this by
+      ** checking the offsetof() for each member. */
+      const sqlite3_index_info siiCheck;
+#define IndexSzCheck(T,M)           \
+      (sizeof(T) == sizeof(*siiCheck.M))
+      if(!IndexSzCheck(sqlite3_index_constraint,aConstraint)
+         || !IndexSzCheck(sqlite3_index_orderby,aOrderBy)
+         || !IndexSzCheck(sqlite3_index_constraint_usage,aConstraintUsage)){
+        assert(!"sizeof mismatch in sqlite3_index_... struct(s)");
+        return 0;
+      }
+#undef IndexSzCheck
+    }
+
+#define CurrentStruct sqlite3_index_constraint
+    StructBinder {
+      M(iColumn,        "i");
+      M(op,             "C");
+      M(usable,         "C");
+      M(iTermOffset,    "i");
+    } _StructBinder;
+#undef CurrentStruct
+
+#define CurrentStruct sqlite3_index_orderby
+    StructBinder {
+      M(iColumn,   "i");
+      M(desc,      "C");
+    } _StructBinder;
+#undef CurrentStruct
+
+#define CurrentStruct sqlite3_index_constraint_usage
+    StructBinder {
+      M(argvIndex,  "i");
+      M(omit,       "C");
+    } _StructBinder;
+#undef CurrentStruct
+
+#define CurrentStruct sqlite3_index_info
+    StructBinder {
+      M(nConstraint,        "i");
+      M(aConstraint,        "p");
+      M(nOrderBy,           "i");
+      M(aOrderBy,           "p");
+      M(aConstraintUsage,   "p");
+      M(idxNum,             "i");
+      M(idxStr,             "p");
+      M(needToFreeIdxStr,   "i");
+      M(orderByConsumed,    "i");
+      M(estimatedCost,      "d");
+      M(estimatedRows,      "j");
+      M(idxFlags,           "i");
+      M(colUsed,            "j");
+    } _StructBinder;
+#undef CurrentStruct
+
 #if SQLITE_WASM_TESTS
 #define CurrentStruct WasmTestStruct
     StructBinder {
index 8cb48332479005fd4aa43b4d71960047e1715b48..84d829daba21d4fc7e3920c364fc49abe16fb063 100644 (file)
@@ -1081,10 +1081,9 @@ self.WhWasmUtilInstaller = function(target){
 
   // impl for allocMainArgv() and scopedAllocMainArgv().
   const __allocMainArgv = function(isScoped, list){
-    if(!list.length) toss("Cannot allocate empty array.");
     const pList = target[
       isScoped ? 'scopedAlloc' : 'alloc'
-    ](list.length * target.ptrSizeof);
+    ]((list.length + 1) * target.ptrSizeof);
     let i = 0;
     list.forEach((e)=>{
       target.setPtrValue(pList + (target.ptrSizeof * i++),
@@ -1092,26 +1091,33 @@ self.WhWasmUtilInstaller = function(target){
                            isScoped ? 'scopedAllocCString' : 'allocCString'
                          ](""+e));
     });
+    target.setPtrValue(pList + (target.ptrSizeof * i), 0);
     return pList;
   };
 
   /**
      Creates an array, using scopedAlloc(), suitable for passing to a
      C-level main() routine. The input is a collection with a length
-     property and a forEach() method. A block of memory list.length
-     entries long is allocated and each pointer-sized block of that
-     memory is populated with a scopedAllocCString() conversion of the
-     (""+value) of each element. Returns a pointer to the start of the
-     list, suitable for passing as the 2nd argument to a C-style
-     main() function.
-
-     Throws if list.length is falsy or scopedAllocPush() is not active.
+     property and a forEach() method. A block of memory
+     (list.length+1) entries long is allocated and each pointer-sized
+     block of that memory is populated with a scopedAllocCString()
+     conversion of the (""+value) of each element, with the exception
+     that the final entry is a NULL pointer. Returns a pointer to the
+     start of the list, suitable for passing as the 2nd argument to a
+     C-style main() function.
+
+     Throws if scopedAllocPush() is not active.
+
+     Design note: the returned array is allocated with an extra NULL
+     pointer entry to accommodate certain APIs, but client code which
+     does not need that functionality should treat the returned array
+     as list.length entries long.
   */
   target.scopedAllocMainArgv = (list)=>__allocMainArgv(true, list);
 
   /**
      Identical to scopedAllocMainArgv() but uses alloc() instead of
-     scopedAllocMainArgv
+     scopedAlloc().
   */
   target.allocMainArgv = (list)=>__allocMainArgv(false, list);
 
index dee7258c5157a788c8f1be889d42deafe09d454b..81b4c1bd4f90f82277b859451f551497f7f69e8d 100644 (file)
@@ -121,6 +121,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
       at SIG s[0]. Throws for an unknown SIG. */
   const sigIR = function(s){
     switch(sigLetter(s)){
+        case 'c': case 'C': return 'i8';
         case 'i': return 'i32';
         case 'p': case 'P': case 's': return ptrIR;
         case 'j': return 'i64';
@@ -133,6 +134,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
       unknown SIG. */
   const sigSizeof = function(s){
     switch(sigLetter(s)){
+        case 'c': case 'C': return 1;
         case 'i': return 4;
         case 'p': case 'P': case 's': return ptrSizeof;
         case 'j': return 8;
@@ -168,6 +170,8 @@ self.Jaccwabyt = function StructBinderFactory(config){
           break;
         }
         case 'i': return 'getInt32';
+        case 'c': return 'getInt8';
+        case 'C': return 'getUint8';
         case 'j': return affirmBigIntArray() && 'getBigInt64';
         case 'f': return 'getFloat32';
         case 'd': return 'getFloat64';
@@ -186,6 +190,8 @@ self.Jaccwabyt = function StructBinderFactory(config){
           break;
         }
         case 'i': return 'setInt32';
+        case 'c': return 'setInt8';
+        case 'C': return 'setUint8';
         case 'j': return affirmBigIntArray() && 'setBigInt64';
         case 'f': return 'setFloat32';
         case 'd': return 'setFloat64';
@@ -199,7 +205,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
   */
   const sigDVSetWrapper = function(s){
     switch(sigLetter(s)) {
-        case 'i': case 'f': case 'd': return Number;
+        case 'i': case 'f': case 'c': case 'C': case 'd': return Number;
         case 'j': return affirmBigIntArray() && BigInt;
         case 'p': case 'P': case 's':
           switch(ptrSizeof){
@@ -361,7 +367,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
      framework's native format or in Emscripten format.
   */
   const __memberSignature = function f(obj,memberName,emscriptenFormat=false){
-    if(!f._) f._ = (x)=>x.replace(/[^vipPsjrd]/g,"").replace(/[pPs]/g,'i');
+    if(!f._) f._ = (x)=>x.replace(/[^vipPsjrdcC]/g,"").replace(/[pPscC]/g,'i');
     const m = __lookupMember(obj.structInfo, memberName, true);
     return emscriptenFormat ? f._(m.signature) : m.signature;
   };
@@ -570,7 +576,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
       /*cache all available getters/setters/set-wrappers for
         direct reuse in each accessor function. */
       f._ = {getters: {}, setters: {}, sw:{}};
-      const a = ['i','p','P','s','f','d','v()'];
+      const a = ['i','c','C','p','P','s','f','d','v()'];
       if(bigIntEnabled) a.push('j');
       a.forEach(function(v){
         //const ir = sigIR(v);
@@ -579,8 +585,8 @@ self.Jaccwabyt = function StructBinderFactory(config){
         f._.sw[v] = sigDVSetWrapper(v)  /* BigInt or Number ctor to wrap around values
                                            for conversion */;
       });
-      const rxSig1 = /^[ipPsjfd]$/,
-            rxSig2 = /^[vipPsjfd]\([ipPsjfd]*\)$/;
+      const rxSig1 = /^[ipPsjfdcC]$/,
+            rxSig2 = /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/;
       f.sigCheck = function(obj, name, key,sig){
         if(Object.prototype.hasOwnProperty.call(obj, key)){
           toss(obj.structName,'already has a property named',key+'.');
@@ -594,7 +600,6 @@ self.Jaccwabyt = function StructBinderFactory(config){
     f.sigCheck(ctor.prototype, name, key, descr.signature);
     descr.key = key;
     descr.name = name;
-    const sizeOf = sigSizeof(descr.signature);
     const sigGlyph = sigLetter(descr.signature);
     const xPropName = sPropName(ctor.prototype.structName,key);
     const dbg = ctor.prototype.debugFlags.__flags;
@@ -610,10 +615,10 @@ self.Jaccwabyt = function StructBinderFactory(config){
     prop.get = function(){
       if(dbg.getter){
         log("debug.getter:",f._.getters[sigGlyph],"for", sigIR(sigGlyph),
-            xPropName,'@', this.pointer,'+',descr.offset,'sz',sizeOf);
+            xPropName,'@', this.pointer,'+',descr.offset,'sz',descr.sizeof);
       }
       let rc = (
-        new DataView(heap().buffer, this.pointer + descr.offset, sizeOf)
+        new DataView(heap().buffer, this.pointer + descr.offset, descr.sizeof)
       )[f._.getters[sigGlyph]](0, isLittleEndian);
       if(dbg.getter) log("debug.getter:",xPropName,"result =",rc);
       if(rc && isAutoPtrSig(descr.signature)){
@@ -628,7 +633,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
       prop.set = function(v){
         if(dbg.setter){
           log("debug.setter:",f._.setters[sigGlyph],"for", sigIR(sigGlyph),
-              xPropName,'@', this.pointer,'+',descr.offset,'sz',sizeOf, v);
+              xPropName,'@', this.pointer,'+',descr.offset,'sz',descr.sizeof, v);
         }
         if(!this.pointer){
           toss("Cannot set struct property on disposed instance.");
@@ -644,7 +649,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
           toss("Invalid value for pointer-type",xPropName+'.');
         }
         (
-          new DataView(heap().buffer, this.pointer + descr.offset, sizeOf)
+          new DataView(heap().buffer, this.pointer + descr.offset, descr.sizeof)
         )[f._.setters[sigGlyph]](0, f._.sw[sigGlyph](v), isLittleEndian);
       };
     }
@@ -665,13 +670,18 @@ self.Jaccwabyt = function StructBinderFactory(config){
     if(!structName) toss("Struct name is required.");
     let lastMember = false;
     Object.keys(structInfo.members).forEach((k)=>{
+      // Sanity checks of sizeof/offset info...
       const m = structInfo.members[k];
       if(!m.sizeof) toss(structName,"member",k,"is missing sizeof.");
-      else if(0!==(m.sizeof%4)){
-        toss(structName,"member",k,"sizeof is not aligned.");
-      }
-      else if(0!==(m.offset%4)){
-        toss(structName,"member",k,"offset is not aligned.");
+      else if(m.sizeof>1){ // offsets of size-1 members may be odd values.
+        if(0!==(m.sizeof%4)){
+          console.warn("Invalid struct description =",m,"from",structInfo.members);
+          toss(structName,"member",k,"sizeof is not aligned. sizeof="+m.sizeof);
+        }
+        if(0!==(m.offset%4)){
+          console.warn("Invalid struct description =",m,"from",structInfo.members);
+          toss(structName,"member",k,"offset is not aligned. offset="+m.offset);
+        }
       }
       if(!lastMember || lastMember.offset < m.offset) lastMember = m;
     });
index edcba260a7425451c33e2ff4ecb569f282cb0a98..73f6bfa9479ebf234af90e77cfc641b6ec75dc04 100644 (file)
@@ -281,21 +281,29 @@ supported letters are:
   signature entry.
 - **`f`** = `float` (4 bytes)
 - **`d`** = `double` (8 bytes)
-- **`p`** = `int32` (but see below!)
+- **`c`** = `int8` (char - see notes below!)
+- **`C`** = `int8` (unsigned char - see notes below!)
+- **`p`** = `int32` (see notes below!)
 - **`P`** = Like `p` but with extra handling. Described below.
-- **`s`** = like `int32` but is a _hint_ that it's a pointer to a string
-  so that _some_ (very limited) contexts may treat it as such, noting
-  such algorithms must, for lack of information to the contrary,
-  assume both that the encoding is UTF-8 and that the pointer's member
-  is NUL-terminated. If that is _not_ the case for a given string
-  member, do not use `s`: use `i` or `p` instead and do any string
-  handling yourself.
+- **`s`** = like `int32` but is a _hint_ that it's a pointer to a
+  string so that _some_ (very limited) contexts may treat it as such,
+  noting that such algorithms must, for lack of information to the
+  contrary, assume both that the encoding is UTF-8 and that the
+  pointer's member is NUL-terminated. If that is _not_ the case for a
+  given string member, do not use `s`: use `i` or `p` instead and do
+  any string handling yourself.
 
 Noting that:
 
 - All of these types are numeric. Attempting to set any struct-bound
   property to a non-numeric value will trigger an exception except in
   cases explicitly noted otherwise.
+- "Char" types: WASM does not define an `int8` type, nor does it
+  distinguish between signed and unsigned. This API treats `c` as
+  `int8` and `C` as `uint8` for purposes of getting and setting values
+  when using the `DataView` class. It is _not_ recommended that client
+  code use these types in new WASM-capable code, but they were added
+  for the sake of binding some immutable legacy code to WASM.
 
 > Sidebar: Emscripten's public docs do not mention `p`, but their
 generated code includes `p` as an alias for `i`, presumably to mean
@@ -317,12 +325,12 @@ Signatures in the form `x(...)` denote function-pointer members and
 form `x()`. For function-type signatures, the strings are formulated
 such that they can be passed to Emscripten's `addFunction()` after
 stripping out the `(` and `)` characters. For good measure, to match
-the public Emscripten docs, `p` should also be replaced with `i`. In
-JavaScript that might look like:
+the public Emscripten docs, `p`, `c`, and `C`, should also be replaced
+with `i`. In JavaScript that might look like:
 
 >  
 ```
-signature.replace(/[^vipPsjfd]/g,'').replace(/[pPs]/g,'i');
+signature.replace(/[^vipPsjfdcC]/g,'').replace(/[pPscC]/g,'i');
 ```
 
 <a name='step-2-pvsp'></a>
index 27a4331f16ca81e8f58a86e1a71c6275d58a5dc0..7d4a4ffa9e9a57b267acb4f08926037a16398b1e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Improved\squery\splanner\scost\sestimates.\s\sFix\sfor\sticket\s[e8b674241947eb3b].
-D 2022-12-05T02:52:37.959
+C Initial\sinfrastructure\sfor\sadding\svirtual\stable/table-valued\sfunction\ssupport\sto\sWASM.
+D 2022-12-05T05:30:03.152
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -503,7 +503,7 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08
 F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62
 F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f
 F ext/wasm/api/sqlite3-api-cleanup.js 680d5ccfff54459db136a49b2199d9f879c8405d9c99af1dda0cc5e7c29056f4
-F ext/wasm/api/sqlite3-api-glue.js 6fe39964605fda3b699f69365eed565b5172d29cab2c49bc057a43f9a93f9f36
+F ext/wasm/api/sqlite3-api-glue.js 6028d0c3e6f475a513040a45612238b749ec6c155181d5bd029d66577ab4d0d6
 F ext/wasm/api/sqlite3-api-oo1.js 91a7d7b9203fb0f031e6ba380a644a7f871e1798b388de399c01ed4087bac9e0
 F ext/wasm/api/sqlite3-api-prologue.js 697a5989ad52a9ba7bc60b5436589bd05885ee2201d84c38c5e9af3876af3ba4
 F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f
@@ -512,7 +512,7 @@ F ext/wasm/api/sqlite3-opfs-async-proxy.js f79dd8d98ef3e0b55c10bb2bee7a3840fa967
 F ext/wasm/api/sqlite3-vfs-helper.js 4ad4faf02e1524bf0296be8452c00b5708dce6faf649468d0377e26a0b299263
 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 29d6487a26b2fb6a471cde52c37ffee7c27ed6a91914b308c247e0706f454ffb
 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
-F ext/wasm/api/sqlite3-wasm.c b0babf8435f31d21f28454fb81433aa538c68b23d0a4a251f0666fdec4e71f59
+F ext/wasm/api/sqlite3-wasm.c 5120fb3419aba02d20cbe1e645b58dae5faeaaae8ccd46b8931ae04d311df9e5
 F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b
 F ext/wasm/api/sqlite3-worker1.js 1e54ea3d540161bcfb2100368a2fc0cad871a207b8336afee1c445715851ec54
 F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
@@ -521,7 +521,7 @@ F ext/wasm/c-pp.c 92285f7bce67ed7b7020b40fde8ed0982c442b63dc33df9dfd4b658d4a6c07
 F ext/wasm/common/SqliteTestUtil.js d8bf97ecb0705a2299765c8fc9e11b1a5ac7f10988bbf375a6558b7ca287067b
 F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
 F ext/wasm/common/testing.css 35889709547d89a6109ff83b25c11bbc91d8dd43aab8722e428655ca98880a06
-F ext/wasm/common/whwasmutil.js c1bc5715cd96728929cc31d788b16152ccbd6b2e111d2e88fbc9725247e67b4f
+F ext/wasm/common/whwasmutil.js 1bc1c973662db7d52763512e67c2369fdbfe9e8bae33069ac89f4fbe40d678b2
 F ext/wasm/demo-123-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
 F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
 F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6
@@ -539,8 +539,8 @@ F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5
 F ext/wasm/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2
 F ext/wasm/index-dist.html c806b6005145b71d64240606e9c6e0bf56878ee8829c66fe7486cebf34b0e6b1
 F ext/wasm/index.html f151b7c7b5cfdc066567d556acd168e769efd4e982286dc5f849a5ee69ecd0ff
-F ext/wasm/jaccwabyt/jaccwabyt.js 95f573de1826474c9605dda620ee622fcb1673ae74f191eb324c0853aa4dcb66
-F ext/wasm/jaccwabyt/jaccwabyt.md 9aa6951b529a8b29f578ec8f0355713c39584c92cf1708f63ba0cf917cb5b68e
+F ext/wasm/jaccwabyt/jaccwabyt.js 7c41784c442aa67f0e86e7c14aa51b3a28e3b21eb579c71c16af3c988fbf966f
+F ext/wasm/jaccwabyt/jaccwabyt.md 50df3ccb7a773634000496a2ccb805dd25cf8cd963696a7deec3209a68c6093b
 F ext/wasm/module-symbols.html 980680c8acfa3c8ae6a5aa223512d1b8e78040ced20f8ba2c382129bc73ec028
 F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06
 F ext/wasm/scratchpad-wasmfs-main.js 4c140457f4d6da9d646a49addd91edb6e9ad1643c6c48e3258b5bce24725dc18
@@ -2065,9 +2065,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P cefc032473ac5ad244c0b6402c541b2f76c0c65a041bda03bfbe7c0e2c11fac2 df3818997b822743ac407dde45c5fd75845ca40f461e31350d86963dffec6cd6
-R 3c93957174c9bb89beba8a6d7c9fdaab
-T +closed df3818997b822743ac407dde45c5fd75845ca40f461e31350d86963dffec6cd6
-U drh
-Z 2d83b2d52ce6d0637e1b84504b86ac00
+P 1b779afa3ed2f35a110e460fc6ed13cba744db85b9924149ab028b100d1e1e12
+R b429259a443dd7b0ac8ceede26128588
+T *branch * wasm-vtab
+T *sym-wasm-vtab *
+T -sym-trunk * Cancelled\sby\sbranch.
+U stephan
+Z bd980b10d448d088ee0cbb8238fc2a43
 # Remove this line to create a well-formed Fossil manifest.
index 452c8ac5d7c3fcc4259c41c42a1ef0da29d2b1ee..f70604b10c6ce6e9eef63ad699738318bd346b66 100644 (file)
@@ -1 +1 @@
-1b779afa3ed2f35a110e460fc6ed13cba744db85b9924149ab028b100d1e1e12
\ No newline at end of file
+c202d7a0398b9aabc2babba5c4c91a313f32bbf37549d419775642bb4aa3936a
\ No newline at end of file