aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api/sqlite3-api-glue.js
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-10-02 20:08:53 +0000
committerstephan <stephan@noemail.net>2022-10-02 20:08:53 +0000
commit92ede964e109695fec79262f8ff007f0c9873187 (patch)
tree9251d4284f00671288c75b9c425379b5d207f9c0 /ext/wasm/api/sqlite3-api-glue.js
parent9892883e9e285bd8f5445ad51be9f6ce8b6cc92b (diff)
downloadsqlite-92ede964e109695fec79262f8ff007f0c9873187.tar.gz
sqlite-92ede964e109695fec79262f8ff007f0c9873187.zip
JS: clean up create_function() wrapper and add support for create_window_function(). Eliminate an extraneous blob copy when a UDF returns a blob. Make use of newfound JS-fu to clean up how sqlite3ApiBootstrap() config is initialized.
FossilOrigin-Name: d3bad9347c5423fa7f19ae729461636f1043c99a1f01f168efa10bebefb1cdd1
Diffstat (limited to 'ext/wasm/api/sqlite3-api-glue.js')
-rw-r--r--ext/wasm/api/sqlite3-api-glue.js157
1 files changed, 104 insertions, 53 deletions
diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js
index 268824d6d..5ca6f4ec2 100644
--- a/ext/wasm/api/sqlite3-api-glue.js
+++ b/ext/wasm/api/sqlite3-api-glue.js
@@ -149,9 +149,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const __exec = wasm.xWrap("sqlite3_exec", "int",
["sqlite3*", "flexible-string", "*", "*", "**"]);
/* Documented in the api object's initializer. */
- capi.sqlite3_exec = function(pDb, sql, callback, pVoid, pErrMsg){
- if(5!==arguments.length){
- return __dbArgcMismatch(pDb,"sqlite3_exec",5);
+ capi.sqlite3_exec = function f(pDb, sql, callback, pVoid, pErrMsg){
+ if(f.length!==arguments.length){
+ return __dbArgcMismatch(pDb,"sqlite3_exec",f.length);
}else if('function' !== typeof callback){
return __exec(pDb, sql, callback, pVoid, pErrMsg);
}
@@ -192,11 +192,20 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
}/*sqlite3_exec() proxy*/;
- if(1){/* Special-case handling of sqlite3_create_function_v2() */
+ if(1){/* Special-case handling of sqlite3_create_function_v2()
+ and sqlite3_create_window_function() */
const sqlite3CreateFunction = wasm.xWrap(
"sqlite3_create_function_v2", "int",
- ["sqlite3*", "string", "int", "int", "*",
- "*", "*", "*", "*"]
+ ["sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
+ "int"/*eTextRep*/, "*"/*pApp*/,
+ "*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/, "*"/*xDestroy*/]
+ );
+ const sqlite3CreateWindowFunction = wasm.xWrap(
+ "sqlite3_create_window_function", "int",
+ ["sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
+ "int"/*eTextRep*/, "*"/*pApp*/,
+ "*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/,
+ "*"/*xInverse*/, "*"/*xDestroy*/]
);
const __setResult = function(pCx, val){
switch(typeof val) {
@@ -213,14 +222,15 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
capi.sqlite3_result_text(pCx, val, -1, capi.SQLITE_TRANSIENT);
break;
case 'object':
- if(null===val) {
+ if(null===val/*yes, typeof null === 'object'*/) {
capi.sqlite3_result_null(pCx);
break;
}else if(util.isBindableTypedArray(val)){
const pBlob = wasm.allocFromTypedArray(val);
- capi.sqlite3_result_blob(pCx, pBlob, val.byteLength,
- capi.SQLITE_TRANSIENT);
- wasm.dealloc(pBlob);
+ capi.sqlite3_result_blob(
+ pCx, pBlob, val.byteLength,
+ wasm.exports[sqlite3.config.deallocExportName]
+ );
break;
}
// else fall through
@@ -277,22 +287,27 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
capi.sqlite3_result_error(pCx, e.message, -1);
}
};
-
+
+ /* TODO: pass on the pCx pointer to all callbacks. This requires
+ fixing test code and updating oodles of docs. Once that is in place,
+ export sqlite3_aggregate_context().
+ */
+
const __xFunc = function(callback){
return function(pCx, argc, pArgv){
- try{__setResult(pCx, callback(...__extractArgs(argc, pArgv)))}
+ try{ __setResult(pCx, callback(...__extractArgs(argc, pArgv))) }
catch(e){ __setCxErr(pCx, e) }
};
};
- const __xStep = function(callback){
+ const __xInverseAndStep = function(callback){
return function(pCx, argc, pArgv){
try{ callback(...__extractArgs(argc, pArgv)) }
catch(e){ __setCxErr(pCx, e) }
};
};
- const __xFinal = function(callback){
+ const __xFinalAndValue = function(callback){
return function(pCx){
try{ __setResult(pCx, callback()) }
catch(e){ __setCxErr(pCx, e) }
@@ -302,11 +317,34 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const __xDestroy = function(callback){
return function(pVoid){
try{ callback(pVoid) }
- catch(e){
- console.error("UDF xDestroy method threw:",e);
- }
+ catch(e){ console.error("UDF xDestroy method threw:",e) }
};
};
+
+ const __xMap = Object.assign(Object.create(null), {
+ xFunc: {sig:'v(pip)', f:__xFunc},
+ xStep: {sig:'v(pip)', f:__xInverseAndStep},
+ xInverse: {sig:'v(pip)', f:__xInverseAndStep},
+ xFinal: {sig:'v(p)', f:__xFinalAndValue},
+ xValue: {sig:'v(p)', f:__xFinalAndValue},
+ xDestroy: {sig:'v(p)', f:__xDestroy}
+ });
+
+ const __xWrapFuncs = function(theFuncs, tgtUninst){
+ const rc = []
+ let k;
+ for(k in theFuncs){
+ let fArg = theFuncs[k];
+ if('function'===typeof fArg){
+ const w = __xMap[k];
+ fArg = wasm.installFunction(w.sig, w.f(fArg));
+ tgtUninst.push(fArg);
+ }
+ rc.push(fArg);
+ }
+ return rc;
+ };
+
/* Documented in the api object's initializer. */
capi.sqlite3_create_function_v2 = function f(
pDb, funcName, nArg, eTextRep, pApp,
@@ -315,34 +353,16 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
xFinal, //void (*xFinal)(sqlite3_context*)
xDestroy //void (*xDestroy)(void*)
){
- if(9!==arguments.length){
- return __dbArgcMismatch(pDb,"sqlite3_create_function_v2",9);
- }
- if(!f._sigs){
- f._wrap = Object.assign(Object.create(null), {
- xFunc: {sig:'v(pip)', f:__xFunc},
- xStep: {sig:'v(pip)', f:__xStep},
- xFinal: {sig:'v(p)', f:__xFinal},
- xDestroy: {sig:'v(p)', f:__xDestroy}
- });
+ if(f.length!==arguments.length){
+ return __dbArgcMismatch(pDb,"sqlite3_create_function_v2",f.length);
}
- const callbacks = [];
/* Wrap the callbacks in a WASM-bound functions... */
const wasm = capi.wasm;
- const funcArgs = [], uninstall = [/*funcs to uninstall on error*/],
- theFuncs = {xFunc, xStep, xFinal, xDestroy};
+ const uninstall = [/*funcs to uninstall on error*/];
let rc;
try{
- let k;
- for(k in theFuncs){
- let fArg = theFuncs[k];
- if('function'===typeof fArg){
- const w = f._wrap[k];
- fArg = wasm.installFunction(w.sig, w.f(fArg));
- uninstall.push(fArg);
- }
- funcArgs.push(fArg);
- }
+ const funcArgs = __xWrapFuncs({xFunc, xStep, xFinal, xDestroy},
+ uninstall);
rc = sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
pApp, ...funcArgs);
}catch(e){
@@ -356,21 +376,52 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return rc;
};
- capi.sqlite3_create_function = function(
+ capi.sqlite3_create_function = function f(
pDb, funcName, nArg, eTextRep, pApp,
xFunc, xStep, xFinal
){
- if(8!==arguments.length){
- return __dbArgcMismatch(pDb,"sqlite3_create_function",8);
- }
- return capi.sqlite3_create_function_v2(pDb, funcName, nArg, eTextRep,
- pApp, xFunc, xStep, xFinal, 0);
+ return (f.length===arguments.length)
+ ? capi.sqlite3_create_function_v2(pDb, funcName, nArg, eTextRep,
+ pApp, xFunc, xStep, xFinal, 0)
+ : __dbArgcMismatch(pDb,"sqlite3_create_function",f.length);
+ };
+ /* Documented in the api object's initializer. */
+ capi.sqlite3_create_window_function = function f(
+ pDb, funcName, nArg, eTextRep, pApp,
+ xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
+ xFinal, //void (*xFinal)(sqlite3_context*)
+ xValue, //void (*xFinal)(sqlite3_context*)
+ xInverse,//void (*xStep)(sqlite3_context*,int,sqlite3_value**)
+ xDestroy //void (*xDestroy)(void*)
+ ){
+ if(f.length!==arguments.length){
+ return __dbArgcMismatch(pDb,"sqlite3_create_window_function",f.length);
+ }
+ /* Wrap the callbacks in a WASM-bound functions... */
+ const wasm = capi.wasm;
+ const uninstall = [/*funcs to uninstall on error*/];
+ let rc;
+ try{
+ const funcArgs = __xWrapFuncs({xStep, xFinal, xValue, xInverse, xDestroy},
+ uninstall);
+ rc = sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
+ pApp, ...funcArgs);
+ }catch(e){
+ console.error("sqlite3_create_function_v2() setup threw:",e);
+ for(let v of uninstall){
+ wasm.uninstallFunction(v);
+ }
+ rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR,
+ "Creation of UDF threw: "+e.message);
+ }
+ return rc;
};
- }/*sqlite3_create_function_v2() proxy*/;
+
+ }/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/;
if(1){/* Special-case handling of sqlite3_prepare_v2() and
- sqlite3_prepare_v3() */
+ sqlite3_prepare_v3() */
/**
Scope-local holder of the two impls of sqlite3_prepare_v2/v3().
*/
@@ -403,8 +454,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/* Documented in the api object's initializer. */
capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){
- if(6!==arguments.length){
- return __dbArgcMismatch(pDb,"sqlite3_prepare_v3",6);
+ if(f.length!==arguments.length){
+ return __dbArgcMismatch(pDb,"sqlite3_prepare_v3",f.length);
}
const [xSql, xSqlLen] = __flexiString(sql, sqlLen);
switch(typeof xSql){
@@ -419,10 +470,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
/* Documented in the api object's initializer. */
- capi.sqlite3_prepare_v2 = function(pDb, sql, sqlLen, ppStmt, pzTail){
- return (5==arguments.length)
+ capi.sqlite3_prepare_v2 = function f(pDb, sql, sqlLen, ppStmt, pzTail){
+ return (f.length===arguments.length)
? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail)
- : __dbArgcMismatch(pDb,"sqlite3_prepare_v2",5);
+ : __dbArgcMismatch(pDb,"sqlite3_prepare_v2",f.length);
};
}/*sqlite3_prepare_v2/v3()*/;