]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add more JS tests. Flesh out the aggregate UDF tests to use sqlite3_aggregate_context...
authorstephan <stephan@noemail.net>
Thu, 20 Oct 2022 21:28:31 +0000 (21:28 +0000)
committerstephan <stephan@noemail.net>
Thu, 20 Oct 2022 21:28:31 +0000 (21:28 +0000)
FossilOrigin-Name: 9d034ef5e1bab7c9651c2450dc85765fa6365d3f1414c711550de858ff8b3ece

ext/wasm/api/sqlite3-api-oo1.js
ext/wasm/api/sqlite3-api-prologue.js
ext/wasm/api/sqlite3-api-worker1.js
ext/wasm/api/sqlite3-wasm.c
ext/wasm/tester1.js
manifest
manifest.uuid

index c2e7eb14f1b1fb57ceb0c86f040e2a8e685eedc2..d101bc17f3fe222bac6472345db8c998802213c0 100644 (file)
@@ -149,9 +149,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
     if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
     oflags |= capi.SQLITE_OPEN_EXRESCODE;
-    const scope = wasm.scopedAllocPush();
+    const stack = wasm.pstack.pointer;
     try {
-      const pPtr = wasm.allocPtr() /* output (sqlite3**) arg */;
+      const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */;
       const pVfsName = vfsName ? (
         ('number'===typeof vfsName ? vfsName : wasm.scopedAllocCString(vfsName))
       ): 0;
@@ -163,21 +163,19 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
                               __dbTraceToConsole, 0);
       }
       // Check for per-VFS post-open SQL...
-      wasm.setPtrValue(pPtr, 0);
-      if(0===capi.sqlite3_file_control(
-        pDb, "main", capi.SQLITE_FCNTL_VFS_POINTER, pPtr
-      )){
-        const postInitSql = __vfsPostOpenSql[wasm.getPtrValue(pPtr)];
-        if(postInitSql){
-          rc = capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0);
-          checkSqlite3Rc(pDb, rc);
-        }
+      const pVfs = capi.sqlite3_js_db_vfs(pDb);
+      //console.warn("Opened db",fn,"with vfs",vfsName,pVfs);
+      if(!pVfs) toss3("Internal error: cannot get VFS for new db handle.");
+      const postInitSql = __vfsPostOpenSql[pVfs];
+      if(postInitSql){
+        rc = capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0);
+        checkSqlite3Rc(pDb, rc);
       }      
     }catch( e ){
       if( pDb ) capi.sqlite3_close_v2(pDb);
       throw e;
     }finally{
-      wasm.scopedAllocPop(scope);
+      wasm.pstack.restore(stack);
     }
     this.filename = fnJs;
     __ptrMap.set(this, pDb);
index ca1542e2b2983abf0ce73d3b7c69564f45ae9aef..da7d0740fa19a465d79402c99e685cfe5dee985d 100644 (file)
@@ -280,6 +280,14 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
       this.name = 'WasmAllocError';
     }
   };
+  /**
+     Functionally equivalent to the WasmAllocError constructor but may
+     be used as part of an expression, e.g.:
+
+     ```
+     return someAllocatingFunction(x) || WasmAllocError.toss(...);
+     ```
+  */
   WasmAllocError.toss = (...args)=>{
     throw new WasmAllocError(args.join(' '));
   };
@@ -508,6 +516,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
        "flexible-string" argument converter.
     */
     sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg)=>{}/*installed later*/,
+
     /**
        Various internal-use utilities are added here as needed. They
        are bound to an object only so that we have access to them in
@@ -1024,6 +1033,14 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
       this.name = 'SQLite3Error';
     }
   };
+  /**
+     Functionally equivalent to the SQLite3Error constructor but may
+     be used as part of an expression, e.g.:
+
+     ```
+     return someFunction(x) || SQLite3Error.toss(...);
+     ```
+  */
   SQLite3Error.toss = (...args)=>{
     throw new SQLite3Error(args.join(' '));
   };
@@ -1096,8 +1113,10 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
      pointer. The 3rd argument specifies the database name of the
      given database connection to check, defaulting to the main db.
 
-     The 2nd and 3rd arguments may either be a JS string or a C-string
-     allocated from the wasm environment.
+     The 2nd and 3rd arguments may either be a JS string or a WASM
+     C-string. If the 2nd argument is a NULL WASM pointer, the default
+     VFS is assumed. If the 3rd is a NULL WASM pointer, "main" is
+     assumed.
 
      The truthy value it returns is a pointer to the `sqlite3_vfs`
      object.
@@ -1112,17 +1131,9 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
       const pK = capi.sqlite3_vfs_find(vfsName);
       if(!pK) return false;
       else if(!pDb){
-        return capi.sqlite3_vfs_find(0)===pK ? pK : false;
-      }
-      const ppVfs = wasm.allocPtr();
-      try{
-        return (
-          (0===capi.sqlite3_file_control(
-            pDb, dbName, capi.SQLITE_FCNTL_VFS_POINTER, ppVfs
-          )) && (wasm.getPtrValue(ppVfs) === pK)
-        ) ? pK : false;
-      }finally{
-        wasm.dealloc(ppVfs);
+        return pK===capi.sqlite3_vfs_find(0) ? pK : false;
+      }else{
+        return pK===capi.sqlite3_js_db_vfs(pDb) ? pK : false;
       }
     }catch(e){
       /* Ignore - probably bad args to a wasm-bound function. */
@@ -1179,14 +1190,32 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
         ? wasm.heap8u().slice(pOut, pOut + Number(nOut))
         : new Uint8Array();
       return rc;
-    }catch(e){
-      console.error('internal error?',e);
-      throw w;
     }finally{
       if(pOut) wasm.exports.sqlite3_free(pOut);
       wasm.pstack.restore(stack);
     }
   };
+
+  /**
+     Given a `sqlite3*` and a database name (JS string or WASM
+     C-string pointer, which may be 0), returns a pointer to the
+     sqlite3_vfs responsible for it. If the given db name is null/0,
+     or not provided, then "main" is assumed.
+  */
+  capi.sqlite3_js_db_vfs =
+    (dbPointer, dbName=0)=>wasm.sqlite3_wasm_db_vfs(dbPointer, dbName);
+
+  /**
+     A thin wrapper around capi.sqlite3_aggregate_context() which
+     behaves the same except that it throws a WasmAllocError if that
+     function returns 0.
+  */
+  capi.sqlite3_js_aggregate_context = (pCtx, n)=>{
+    return capi.sqlite3_aggregate_context(pCtx, n)
+      || WasmAllocError.toss(
+        "Cannot allocate",n,"bytes for sqlite3_aggregate_context()"
+      );
+  };
   
   if( capi.util.isMainWindow() ){
     /* Features specific to the main window thread... */
index fa6a4384627c21bb4f9c513fd225a799ae8101ed..dea06341a01cbcaa5ca733e4b3aa2466719e69dd 100644 (file)
 
   If the `dbId` does not refer to an opened ID, this is a no-op. If
   the `args` object contains a truthy `unlink` value then the database
-  will unlinked (deleted) after closing it. The inability to close a
+  will be unlinked (deleted) after closing it. The inability to close a
   db (because it's not opened) or delete its file does not trigger an
   error.
 
index 1decf0593f6b295f3c9e5003961002041d3a9090..8b767948e4ad94e32106f174e170800ad15973f1 100644 (file)
@@ -48,6 +48,7 @@
 ** want undefined. Please keep these alphabetized.
 */
 #undef SQLITE_OMIT_DESERIALIZE
+#undef SQLITE_OMIT_MEMORYDB
 
 /*
 ** Define any SQLITE_... config defaults we want if they aren't
index c8808c9137a4660a5b2c82949125ade7fa940fda..0d4dd3bcfc4b0e1af6dc176363d8ab78f64aed62 100644 (file)
         .assert(0===this.db.openStatementCount());
     })
 
+  ////////////////////////////////////////////////////////////////////////
+    .t('sqlite3_js_...()', function(){
+      const db = this.db;
+      if(1){
+        const vfsList = capi.sqlite3_js_vfs_list();
+        T.assert(vfsList.length>1);
+        T.assert('string'===typeof vfsList[0]);
+
+        for(const v of vfsList){
+          T.assert('string' === typeof v)
+            .assert(capi.sqlite3_vfs_find(v) > 0);
+        }
+      }
+      /**
+         Trivia: the magic db name ":memory:" does not actually use the
+         "memdb" VFS unless "memdb" is _explicitly_ provided as the VFS
+         name. Instead, it uses the default VFS with an in-memory btree.
+         Thus this.db's VFS may not be memdb even though it's an in-memory
+         db.
+      */
+      const pVfsMem = capi.sqlite3_vfs_find('memdb'),
+            pVfsDflt = capi.sqlite3_vfs_find(0),
+            pVfsDb = capi.sqlite3_js_db_vfs(db.pointer);
+      T.assert(pVfsMem > 0)
+        .assert(pVfsDflt > 0)
+        .assert(pVfsDb > 0)
+        .assert(pVfsMem !== pVfsDflt
+                /* memdb lives on top of the default vfs */)
+        .assert(':memory:' === db.filename)
+        .assert(pVfsDb === pVfsDflt || pVfsdb === pVfsMem)
+      ;
+      /*const vMem = new capi.sqlite3_vfs(pVfsMem),
+        vDflt = new capi.sqlite3_vfs(pVfsDflt),
+        vDb = new capi.sqlite3_vfs(pVfsDb);*/
+      const duv = capi.sqlite3_js_db_uses_vfs;
+      T.assert(pVfsDflt === duv(db.pointer, 0)
+               || pVfsMem === duv(db.pointer,0))
+        .assert(!duv(db.pointer, "foo"))
+      ;
+    }/*sqlite3_js_...()*/)
+
   ////////////////////////////////////////////////////////////////////
     .t('Table t', function(sqlite3){
       const db = this.db;
           .assert(0==e.message.indexOf('Cannot prepare empty'));
       }
     })
+  ////////////////////////////////////////////////////////////////////////
+    .t('sqlite3_js_db_export()', function(){
+      const db = this.db;
+      const xp = capi.sqlite3_js_db_export(db.pointer);
+      T.assert(xp instanceof Uint8Array)
+        .assert(xp.byteLength>0)
+        .assert(0 === xp.byteLength % 512);
+    }/*sqlite3_js_db_export()*/)
 
   ////////////////////////////////////////////////////////////////////
     .t('Scalar UDFs', function(sqlite3){
       name: 'Aggregate UDFs',
       test: function(sqlite3){
         const db = this.db;
-        const aggState = {summer: 0, summerN: 0};
+        const sjac = capi.sqlite3_js_aggregate_context;
         db.createFunction({
           name: 'summer',
           xStep: function(pCtx, n){
-            aggState.summer += n;
+            const pAgg = sjac(pCtx, 4);
+            wasm.setMemValue(pAgg, wasm.getMemValue(pAgg,'i32') + Number(n), 'i32');
           },
-          xFinal: function(pCtx){
-            const rc = aggState.summer;
-            aggState.summer = 0;
-            return rc;
-          }
+          xFinal: (pCtx)=>wasm.getMemValue(sjac(pCtx, 4),'i32')
         });
         let v = db.selectValue([
           "with cte(v) as (",
           "select 3 union all select 5 union all select 7",
-          ") select summer(v) from cte"
+          ") select summer(v), summer(v+1) from cte"
+          /* ------------------^^^^^^^^^^^ ensures that we're handling
+              sqlite3_aggregate_context() properly. */
         ]);
         T.assert(15===v);
         T.mustThrowMatching(()=>db.selectValue("select summer(1,2)"),
                             /wrong number of arguments/);
+
         db.createFunction({
           name: 'summerN',
           arity: -1,
           xStep: function(pCtx, ...args){
-            for(const v of args) aggState.summerN += v;
+            const pAgg = sjac(pCtx, 4);
+            let sum = wasm.getMemValue(pAgg, 'i32');
+            for(const v of args) sum += Number(v);
+            wasm.setMemValue(pAgg, sum, 'i32');
           },
           xFinal: function(pCtx){
-            const rc = aggState.summerN;
-            aggState.summerN = 0;
-            return rc;
+            return wasm.getMemValue(sjac(pCtx, 4),'i32')
           }
         }); 
-        T.assert(18===db.selectValue('select summerN(1,8,9)'));
+        T.assert(18===db.selectValue('select summerN(1,8,9), summerN(2,3,4)'));
         T.mustThrowMatching(()=>{
           db.createFunction('nope',{
             xFunc: ()=>{}, xStep: ()=>{}
      }
     }/*aggregate UDFs*/)
 
+  ////////////////////////////////////////////////////////////////////////
+    .t({
+      name: 'Aggregate UDFs (64-bit)',
+      predicate: ()=>wasm.bigIntEnabled,
+      test: function(sqlite3){
+        const db = this.db;
+        const sjac = capi.sqlite3_js_aggregate_context;
+        db.createFunction({
+          name: 'summer64',
+          xStep: function(pCtx, n){
+            const pAgg = sjac(pCtx, 8);
+            wasm.setMemValue(pAgg, wasm.getMemValue(pAgg,'i64') + BigInt(n), 'i64');
+          },
+          xFinal: (pCtx)=>wasm.getMemValue(sjac(pCtx, 8),'i64')
+        });
+        let v = db.selectValue([
+            "with cte(v) as (",
+          "select 3 union all select 5 union all select 7",
+          ") select summer64(v*10), summer64(v+1) from cte"
+        ]);
+        T.assert(150n===BigInt(v));
+     }
+    }/*aggregate UDFs*/)
+
   ////////////////////////////////////////////////////////////////////
     .t({
       name: 'Window UDFs (tests are TODO)',
index 1e1b0ee252d9c3d7de785b698fbc0e99f155aa47..40a970ee62e14ef4ec4ad78ec99361e54f500ea8 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Apply\smagic.txt\scorrection\sand\saddition\sreported\sin\s[forum\spost\s2d2366a04a0385|forum:2d2366a04a0385].
-D 2022-10-20T18:58:14.289
+C Add\smore\sJS\stests.\sFlesh\sout\sthe\saggregate\sUDF\stests\sto\suse\ssqlite3_aggregate_context()\sso\sthat\sthey\scan\seach\sbe\sused\smultiple\stimes\sin\sthe\ssame\sstatement.\sAdd\ssqlite3_js_aggregate_context()\sconvenience\shelper.
+D 2022-10-20T21:28:31.440
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -485,14 +485,14 @@ F ext/wasm/api/post-js-header.js 2e5c886398013ba2af88028ecbced1e4b22dc96a86467f1
 F ext/wasm/api/pre-js.js 151e0616614a49f3db19ed544fa13b38c87c108959fbcd4029ea8399a562d94f
 F ext/wasm/api/sqlite3-api-cleanup.js 4d07a7524dc9b7b050acfde57163e839243ad2383bd7ee0de0178b1b3e988588
 F ext/wasm/api/sqlite3-api-glue.js 0b5240bd325d2561f269cd0d82bf686336526e5e276251c2241adfbda802abf8
-F ext/wasm/api/sqlite3-api-oo1.js dc9b6a61649ad32836044de388c5248790239d62ced4e1116023135fcb0fc68b
+F ext/wasm/api/sqlite3-api-oo1.js 0e278d131dad72e9eb348a3dda6a4ff734a9e08925b4ed7e6e5a688d2edaf525
 F ext/wasm/api/sqlite3-api-opfs.js 22d60ba956e873b65e2e0591e239178082bd53a6d563c3c58db7dc03e562e8f7
-F ext/wasm/api/sqlite3-api-prologue.js 1366d538a7b388c299a389f441a79cf0b18af50208343545bd318936b6232acd
-F ext/wasm/api/sqlite3-api-worker1.js cb07b321164483524a27cf2207d4358b905703c410fcd8256e0acca5ab2fffb2
+F ext/wasm/api/sqlite3-api-prologue.js bb7a98a8c62545bf07b5fdee831c0d40c86f98c0094b00d8497a9de8976a0544
+F ext/wasm/api/sqlite3-api-worker1.js a7f38f03275d6c27ab2aef3e83215d3c97ce09c43e6904df47c3764d9d4572b4
 F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
 F ext/wasm/api/sqlite3-opfs-async-proxy.js 206ce6bbc3c30ad51a37d9c25e3a2712e70b586e0f9a2cf8cb0b9619017c2671
 F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
-F ext/wasm/api/sqlite3-wasm.c e1fcda97775dd149b4a2e0a4f16a22cede96daa5a91795ba214bdb3c2e680f4a
+F ext/wasm/api/sqlite3-wasm.c dde771a10e6a8d01ae516d32abc4cdd2d542cb3339e35c5b4be8ebbc1dc1ccc1
 F ext/wasm/api/sqlite3-worker1-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b
 F ext/wasm/api/sqlite3-worker1.js dbe54b69c1520a2d25eae148cd2750ded2dd7f219ea4ee46f83e0a851dca5974
 F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
@@ -533,7 +533,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
 F ext/wasm/test-opfs-vfs.js 48fc59110e8775bb43c9be25b6d634fc07ebadab7da8fbd44889e8129c6e2548
 F ext/wasm/tester1-worker.html 048c341f124fdb61ca14dfd1bd1f78742490f208aa3bb1e84399f83f1e7e6a74
 F ext/wasm/tester1.html 37ccc958fa0d95074af2d72b7241c8e2d982bbec6dda4dc790241af3d933c3b6
-F ext/wasm/tester1.js 44d71175e2941bf1d7c27afa0c395fe81c83cbd74cd10e34e0688dd833042f1e
+F ext/wasm/tester1.js 6e1c8e4d48add1d49fb7901dfee04fdf6cdd5bc39adcbf15c097f61b581a893c
 F ext/wasm/version-info.c 5fa356d38859d71a0369b5c37e1935def7413fcc8a4e349a39d9052c1d0479f4
 F ext/wasm/wasmfs.make ee0004813e16c283ff633e08b482008d56adf9b7d42f6c5612f7ab002b924f69
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
@@ -2036,8 +2036,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 ac9af71b72a749b0a040273a88480d56f49570b569389a4ea20cc055f494d8ff
-R b44d84c26c2f9b06f7e9b798ca72a049
+P 9bf26e2aa3579f354ed2d314e1bf3e3ef117cbd71500ef5f76caa1de5cce1edc
+R dbe97bbb80fe6071199461fb846ef1aa
 U stephan
-Z e01cdee717736d0716b4f5500835f6af
+Z 83bd13decfea9b8d2129079a8ff06725
 # Remove this line to create a well-formed Fossil manifest.
index 0796abfc385f3c46e8b59e97a768e1b8c37971ca..a3b802fb1bbc3f4f44b593453e59bb088c3387b1 100644 (file)
@@ -1 +1 @@
-9bf26e2aa3579f354ed2d314e1bf3e3ef117cbd71500ef5f76caa1de5cce1edc
\ No newline at end of file
+9d034ef5e1bab7c9651c2450dc85765fa6365d3f1414c711550de858ff8b3ece
\ No newline at end of file