]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Refactor the internal JS routines for converting UDF results and errors to JS into...
authorstephan <stephan@noemail.net>
Sat, 10 Dec 2022 10:24:46 +0000 (10:24 +0000)
committerstephan <stephan@noemail.net>
Sat, 10 Dec 2022 10:24:46 +0000 (10:24 +0000)
FossilOrigin-Name: 35d1d63c7d60119b64341c561294890812837d5432d1d7bed3ed88d6212fbfa0

ext/wasm/api/sqlite3-api-glue.js
ext/wasm/api/sqlite3-api-prologue.js
manifest
manifest.uuid

index e98393df6d14dcd3f97b832150aa7b6fec51451a..89420cbf5d1acf97cce655b10c821dded8aaf8fa 100644 (file)
@@ -324,102 +324,31 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
        "*"/*xInverse*/, "*"/*xDestroy*/]
     );
 
-    const __udfSetResult = function(pCtx, val){
-      //console.warn("udfSetResult",typeof val, val);
-      switch(typeof val) {
-          case 'undefined':
-            /* Assume that the client already called sqlite3_result_xxx(). */
-            break;
-          case 'boolean':
-            capi.sqlite3_result_int(pCtx, val ? 1 : 0);
-            break;
-          case 'bigint':
-            if(wasm.bigIntEnabled){
-              if(util.bigIntFits64(val)) capi.sqlite3_result_int64(pCtx, val);
-              else toss3("BigInt value",val.toString(),"is too BigInt for int64.");
-            }else if(util.bigIntFits32(val)){
-              capi.sqlite3_result_int(pCtx, Number(val));
-            }else if(util.bigIntFitsDouble(val)){
-              capi.sqlite3_result_double(pCtx, Number(val));
-            }else{
-              toss3("BigInt value",val.toString(),"is too BigInt.");
-            }
-            break;
-          case 'number': {
-            (util.isInt32(val)
-             ? capi.sqlite3_result_int
-             : capi.sqlite3_result_double)(pCtx, val);
-            break;
-          }
-          case 'string':
-            capi.sqlite3_result_text(pCtx, val, -1, capi.SQLITE_TRANSIENT);
-            break;
-          case 'object':
-            if(null===val/*yes, typeof null === 'object'*/) {
-              capi.sqlite3_result_null(pCtx);
-              break;
-            }else if(util.isBindableTypedArray(val)){
-              const pBlob = wasm.allocFromTypedArray(val);
-              capi.sqlite3_result_blob(
-                pCtx, pBlob, val.byteLength,
-                wasm.exports[sqlite3.config.deallocExportName]
-              );
-              break;
-            }
-            // else fall through
-          default:
-          toss3("Don't not how to handle this UDF result value:",(typeof val), val);
-      };
-    }/*__udfSetResult()*/;
-
-    const __udfConvertArgs = function(argc, pArgv){
-      let i;
-      const tgt = [];
-      for(i = 0; i < argc; ++i){
-        /**
-           Curiously: despite ostensibly requiring 8-byte
-           alignment, the pArgv array is parcelled into chunks of
-           4 bytes (1 pointer each). The values those point to
-           have 8-byte alignment but the individual argv entries
-           do not.
-        */
-        tgt.push(capi.sqlite3_value_to_js(
-          wasm.peekPtr(pArgv + (wasm.ptrSizeof * i))
-        ));
-      }
-      return tgt;
-    }/*__udfConvertArgs()*/;
-
-    const __udfSetError = (pCtx, e)=>{
-      if(e instanceof sqlite3.WasmAllocError){
-        capi.sqlite3_result_error_nomem(pCtx);
-      }else{
-        const msg = ('string'===typeof e) ? e : e.message;
-        capi.sqlite3_result_error(pCtx, msg, -1);
-      }
-    };
-
     const __xFunc = function(callback){
       return function(pCtx, argc, pArgv){
-        try{ __udfSetResult(pCtx, callback(pCtx, ...__udfConvertArgs(argc, pArgv))) }
-        catch(e){
+        try{
+          capi.sqlite3_result_js(
+            pCtx,
+            callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv))
+          );
+        }catch(e){
           //console.error('xFunc() caught:',e);
-          __udfSetError(pCtx, e);
+          capi.sqlite3_result_error_js(pCtx, e);
         }
       };
     };
 
     const __xInverseAndStep = function(callback){
       return function(pCtx, argc, pArgv){
-        try{ callback(pCtx, ...__udfConvertArgs(argc, pArgv)) }
-        catch(e){ __udfSetError(pCtx, e) }
+        try{ callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) }
+        catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
       };
     };
 
     const __xFinalAndValue = function(callback){
       return function(pCtx){
-        try{ __udfSetResult(pCtx, callback(pCtx)) }
-        catch(e){ __udfSetError(pCtx, e) }
+        try{ capi.sqlite3_result_js(pCtx, callback(pCtx)) }
+        catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
       };
     };
 
@@ -525,61 +454,28 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
       return rc;
     };
     /**
-       A helper for UDFs implemented in JS and bound to WASM by the
-       client. Given a JS value, udfSetResult(pCtx,X) calls one of the
-       sqlite3_result_xyz(pCtx,...)  routines, depending on X's data
-       type:
-
-       - `null`: sqlite3_result_null()
-       - `boolean`: sqlite3_result_int()
-       - `number`: sqlite3_result_int() or sqlite3_result_double()
-       - `string`: sqlite3_result_text()
-       - Uint8Array or Int8Array: sqlite3_result_blob()
-       - `undefined`: indicates that the UDF called one of the
-         `sqlite3_result_xyz()` routines on its own, making this
-         function a no-op. Results are _undefined_ if this function is
-         passed the `undefined` value but did _not_ call one of the
-         `sqlite3_result_xyz()` routines.
-
-       Anything else triggers sqlite3_result_error().
+       A _deprecated_ alias for capi.sqlite3_result_js() which
+       predates the addition of that function in the public API.
     */
     capi.sqlite3_create_function_v2.udfSetResult =
       capi.sqlite3_create_function.udfSetResult =
-      capi.sqlite3_create_window_function.udfSetResult = __udfSetResult;
+      capi.sqlite3_create_window_function.udfSetResult = capi.sqlite3_result_js;
 
     /**
-       A helper for UDFs implemented in JS and bound to WASM by the
-       client. When passed the
-       (argc,argv) values from the UDF-related functions which receive
-       them (xFunc, xStep, xInverse), it creates a JS array
-       representing those arguments, converting each to JS in a manner
-       appropriate to its data type: numeric, text, blob
-       (Uint8Array), or null.
-
-       Results are undefined if it's passed anything other than those
-       two arguments from those specific contexts.
-
-       Thus an argc of 4 will result in a length-4 array containing
-       the converted values from the corresponding argv.
-
-       The conversion will throw only on allocation error or an internal
-       error.
+       A _deprecated_ alias for capi.sqlite3_values_to_js() which
+       predates the addition of that function in the public API.
     */
     capi.sqlite3_create_function_v2.udfConvertArgs =
       capi.sqlite3_create_function.udfConvertArgs =
-      capi.sqlite3_create_window_function.udfConvertArgs = __udfConvertArgs;
+      capi.sqlite3_create_window_function.udfConvertArgs = capi.sqlite3_values_to_js;
 
     /**
-       A helper for UDFs implemented in JS and bound to WASM by the
-       client. It expects to be a passed `(sqlite3_context*, Error)`
-       (an exception object or message string). And it sets the
-       current UDF's result to sqlite3_result_error_nomem() or
-       sqlite3_result_error(), depending on whether the 2nd argument
-       is a sqlite3.WasmAllocError object or not.
+       A _deprecated_ alias for capi.sqlite3_result_error_js() which
+       predates the addition of that function in the public API.
     */
     capi.sqlite3_create_function_v2.udfSetError =
       capi.sqlite3_create_function.udfSetError =
-      capi.sqlite3_create_window_function.udfSetError = __udfSetError;
+      capi.sqlite3_create_window_function.udfSetError = capi.sqlite3_result_error_js;
 
   }/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/;
 
index e28f459c2e36b4f70e9ab8c696131e8773360f2f..21958180185746a6781a8f60b9ca1a0d520bd533 100644 (file)
@@ -1672,9 +1672,11 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
 
      By default it throws if it cannot determine any sensible
      conversion. If passed a falsy second argument, it instead returns
-     `undefined` if no suitable conversion is found. Note that there
+     `undefined` if no suitable conversion is found.  Note that there
      is no conversion from SQL to JS which results in the `undefined`
-     value, so `undefined` has an unambiguous meaning here.
+     value, so `undefined` has an unambiguous meaning here.  It will
+     always throw a WasmAllocError if allocating memory for a
+     conversion fails.
 
      Caveats:
 
@@ -1723,6 +1725,141 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
     return arg;
   };
 
+  /**
+     Requires a C-style array of `sqlite3_value*` objects and the
+     number of entries in that array. Returns a JS array containing
+     the results of passing each C array entry to
+     sqlite3_value_to_js(). The 3rd argument to this function is
+     passed on as the 2nd argument to that one.
+  */
+  capi.sqlite3_values_to_js = function(argc,pArgv,throwIfCannotConvert=true){
+    let i;
+    const tgt = [];
+    for(i = 0; i < argc; ++i){
+      /**
+         Curiously: despite ostensibly requiring 8-byte
+         alignment, the pArgv array is parcelled into chunks of
+         4 bytes (1 pointer each). The values those point to
+         have 8-byte alignment but the individual argv entries
+         do not.
+      */
+      tgt.push(capi.sqlite3_value_to_js(
+        wasm.peekPtr(pArgv + (wasm.ptrSizeof * i))
+      ));
+    }
+    return tgt;
+  };
+
+  /**
+     Calls either sqlite3_result_error_nomem(), if e is-a
+     WasmAllocError, or sqlite3_result_error(). In the latter case,
+     the second arugment is coerced to a string to create the error
+     message.
+
+     The first argument is a (sqlite3_context*). Returns void.
+     Does not throw.
+  */
+  capi.sqlite3_result_error_js = function(pCtx,e){
+    if(e instanceof WasmAllocError){
+      capi.sqlite3_result_error_nomem(pCtx);
+    }else{
+      /* Maintenance reminder: ''+e, rather than e.message,
+         will prefix e.message with e.name, so it includes
+         the exception's type name in the result. */;
+      capi.sqlite3_result_error(pCtx, ''+e, -1);
+    }
+  };
+  
+  /**
+     This function passes its 2nd argument to one of the
+     sqlite3_result_xyz() routines, depending on the type of that
+     argument:
+
+     - If (val instanceof Error), this function passes it to
+       sqlite3_result_error_js().
+     - `null`: `sqlite3_result_null()`
+     - `boolean`: `sqlite3_result_int()` with a value of 0 or 1.
+     - `number`: `sqlite3_result_int()`, `sqlite3_result_int64()`, or
+       `sqlite3_result_double()`, depending on the range of the number
+       and whether or not int64 support is enabled.
+     - `bigint`: similar to `number` but will trigger an error if the
+       value is too big to store in an int64.
+     - `string`: `sqlite3_result_text()`
+     - Uint8Array or Int8Array: `sqlite3_result_blob()`
+     - `undefined`: is a no-op provided to simplify certain use cases.
+
+     Anything else triggers `sqlite3_result_error()` with a
+     description of the problem.
+
+     The first argument to this function is a `(sqlite3_context*)`.
+     Returns void. Does not throw.
+  */
+  capi.sqlite3_result_js = function(pCtx,val){
+    if(val instanceof Error){
+      capi.sqlite3_result_error_js(pCtx, val);
+      return;
+    }
+    try{
+      switch(typeof val) {
+          case 'undefined':
+            /* This is a no-op. This routine originated in the create_function()
+               family of APIs and in that context, passing in undefined indicated
+               that the caller was responsible for calling sqlite3_result_xxx()
+               (if needed). */
+            break;
+          case 'boolean':
+            capi.sqlite3_result_int(pCtx, val ? 1 : 0);
+            break;
+          case 'bigint':
+            if(util.bigIntFits32(val)){
+              capi.sqlite3_result_int(pCtx, Number(val));
+            }else if(util.bigIntFitsDouble(val)){
+              capi.sqlite3_result_double(pCtx, Number(val));
+            }else if(wasm.bigIntEnabled){
+              if(util.bigIntFits64(val)) capi.sqlite3_result_int64(pCtx, val);
+              else toss3("BigInt value",val.toString(),"is too BigInt for int64.");
+            }else{
+              toss3("BigInt value",val.toString(),"is too BigInt.");
+            }
+            break;
+          case 'number': {
+            let f;
+            if(util.isInt32(val)){
+              f = capi.sqlite3_result_int;
+            }else if(wasm.bigIntEnabled
+                     && Number.isInteger(val)
+                     && util.bigIntFits64(BigInt(val))){
+              f = capi.sqlite3_result_int64;
+            }else{
+              f = capi.sqlite3_result_double;
+            }
+            f(pCtx, val);
+            break;
+          }
+          case 'string':
+            capi.sqlite3_result_text(pCtx, val, -1, capi.SQLITE_TRANSIENT);
+            break;
+          case 'object':
+            if(null===val/*yes, typeof null === 'object'*/) {
+              capi.sqlite3_result_null(pCtx);
+              break;
+            }else if(util.isBindableTypedArray(val)){
+              const pBlob = wasm.allocFromTypedArray(val);
+              capi.sqlite3_result_blob(
+                pCtx, pBlob, val.byteLength,
+                wasm.exports[sqlite3.config.deallocExportName]
+              );
+              break;
+            }
+            // else fall through
+          default:
+            toss3("Don't not how to handle this UDF result value:",(typeof val), val);
+      }
+    }catch(e){
+      capi.sqlite3_result_error_js(pCtx, e);
+    }
+  };
+
   /* The remainder of the API will be set up in later steps. */
   const sqlite3 = {
     WasmAllocError: WasmAllocError,
index 002a06aa59f0edc295778b425f801a198333396c..b61347d07443148b485da0f0e5c93c82da7b22b3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Export\ssqlite3_result_subtype()\sand\ssqlite3_value_dup/free/subtype()\sto\sWASM.
-D 2022-12-09T15:26:58.074
+C Refactor\sthe\sinternal\sJS\sroutines\sfor\sconverting\sUDF\sresults\sand\serrors\sto\sJS\sinto\spublic\sAPIs.
+D 2022-12-10T10:24:46.478
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -503,9 +503,9 @@ 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 88e62a380b39a924728d9ed4f74f5424f0ea36e8d124df7da9268cc01ad0b191
+F ext/wasm/api/sqlite3-api-glue.js fc2b58b3309fa404d3e58499609e5c5b17177687f53f1a6703c50067904d7f72
 F ext/wasm/api/sqlite3-api-oo1.js 6d10849609231ccd46fa11b1d3fbbe0f45d9fe84c66a0b054601036540844300
-F ext/wasm/api/sqlite3-api-prologue.js 2582c5a983e6213687153125a12e7f7496a1cd474ee24d777675b104028b0a61
+F ext/wasm/api/sqlite3-api-prologue.js 5173cf1f434410c40fa7c6c6c77aca2a969ef7750f9e099175439d6f9c381407
 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
@@ -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 de8fc4bf34f80f320012a0e506ed8e3e24806daf67845d5dabb00b916108f6ef
-R cd32a70b8175f1ae6d43525e76cb6794
+P 4600a7bbdc4cbe14591d48ea19fe5f7de3a0c10a14cdd97fd51e263a13163d10
+R 87bf3540e42b9fcd39b8a805ab39f0fe
 U stephan
-Z 75119f06284b4ae77a74934eba10a318
+Z e910f830b2b784709a3d3c5d3fc7fb9d
 # Remove this line to create a well-formed Fossil manifest.
index f1bb03e96165054fa0fda1f5e22a6748343bf90d..d197721fccb2b639d3d60d02a4a37707bedd72c5 100644 (file)
@@ -1 +1 @@
-4600a7bbdc4cbe14591d48ea19fe5f7de3a0c10a14cdd97fd51e263a13163d10
\ No newline at end of file
+35d1d63c7d60119b64341c561294890812837d5432d1d7bed3ed88d6212fbfa0
\ No newline at end of file