aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/api
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2022-12-23 21:23:26 +0000
committerstephan <stephan@noemail.net>2022-12-23 21:23:26 +0000
commitbb769f0b4a025761fa2f5150582cf7736cb14345 (patch)
tree23c7c0643f8a95efcbaf728af8b7bba0057c0cd5 /ext/wasm/api
parent77eac0507c7f36a50814336fb1da6a5c3923ffec (diff)
parentab9c2d571e5927060c65d7bfd3132348f6240159 (diff)
downloadsqlite-bb769f0b4a025761fa2f5150582cf7736cb14345.tar.gz
sqlite-bb769f0b4a025761fa2f5150582cf7736cb14345.zip
Merge trunk into wasm-session-api branch.
FossilOrigin-Name: 6cdb036d8e8c5ddb0c6578aeefe318e74d7a90228e57b9f9047057dae3252963
Diffstat (limited to 'ext/wasm/api')
-rw-r--r--ext/wasm/api/sqlite3-api-glue.js103
-rw-r--r--ext/wasm/api/sqlite3-api-oo1.js31
-rw-r--r--ext/wasm/api/sqlite3-api-prologue.js8
3 files changed, 74 insertions, 68 deletions
diff --git a/ext/wasm/api/sqlite3-api-glue.js b/ext/wasm/api/sqlite3-api-glue.js
index f5a6c5753..25201f580 100644
--- a/ext/wasm/api/sqlite3-api-glue.js
+++ b/ext/wasm/api/sqlite3-api-glue.js
@@ -53,7 +53,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
["sqlite3_bind_pointer", "int",
"sqlite3_stmt*", "int", "*", "string:static", "*"],
- ["sqlite3_bind_text","int", "sqlite3_stmt*", "int", "string", "int", "int"
+ ["sqlite3_bind_text","int", "sqlite3_stmt*", "int", "string", "int", "*"
/* We should arguably create a hand-written binding of
bind_text() which does more flexible text conversion, along
the lines of sqlite3_prepare_v3(). The slightly problematic
@@ -481,9 +481,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
{/* Convert Arrays and certain TypedArrays to strings for
'string:flexible'-type arguments */
- const xString = wasm.xWrap.argAdapter('string');
+ const __xString = wasm.xWrap.argAdapter('string');
wasm.xWrap.argAdapter(
- 'string:flexible', (v)=>xString(util.flexibleString(v))
+ 'string:flexible', (v)=>__xString(util.flexibleString(v))
);
/**
@@ -513,12 +513,12 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if(wasm.isPtr(v)) return v;
v = ''+v;
let rc = this[v];
- return rc || (rc = this[v] = wasm.allocCString(v));
+ return rc || (this[v] = wasm.allocCString(v));
}.bind(Object.create(null))
);
}/* special-case string-type argument conversions */
-
- if(1){// WhWasmUtil.xWrap() bindings...
+
+ if(1){// wasm.xWrap() bindings...
/**
Add some descriptive xWrap() aliases for '*' intended to (A)
initially improve readability/correctness of
@@ -562,19 +562,22 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
VFS in many contexts. We specifically do not want that
behavior here. */
return capi.sqlite3_vfs_find(v)
- || sqlite3.SQLite3Error.toss("Unknown sqlite3_vfs name:",v);
+ || sqlite3.SQLite3Error.toss(
+ capi.SQLITE_NOTFOUND,
+ "Unknown sqlite3_vfs name:", v
+ );
}
return aPtr((v instanceof (capi.sqlite3_vfs || nilType))
? v.pointer : v);
});
- const rPtr = wasm.xWrap.resultAdapter('*');
- wasm.xWrap.resultAdapter('sqlite3*', rPtr)
- ('sqlite3_context*', rPtr)
- ('sqlite3_stmt*', rPtr)
- ('sqlite3_value*', rPtr)
- ('sqlite3_vfs*', rPtr)
- ('void*', rPtr);
+ const __xRcPtr = wasm.xWrap.resultAdapter('*');
+ wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr)
+ ('sqlite3_context*', __xRcPtr)
+ ('sqlite3_stmt*', __xRcPtr)
+ ('sqlite3_value*', __xRcPtr)
+ ('sqlite3_vfs*', __xRcPtr)
+ ('void*', __xRcPtr);
/**
Populate api object with sqlite3_...() by binding the "raw" wasm
@@ -588,10 +591,12 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
/* For C API functions which cannot work properly unless
- wasm.bigIntEnabled is true, install a bogus impl which
- throws if called when bigIntEnabled is false. */
+ wasm.bigIntEnabled is true, install a bogus impl which throws
+ if called when bigIntEnabled is false. The alternative would be
+ to elide these functions altogether, which seems likely to
+ cause more confusion. */
const fI64Disabled = function(fname){
- return ()=>toss(fname+"() disabled due to lack",
+ return ()=>toss(fname+"() is unavailable due to lack",
"of BigInt support in this build.");
};
for(const e of wasm.bindingSignatures.int64){
@@ -614,7 +619,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
- (sqlite3*, int code, string msg)
- (sqlite3*, Error e [,string msg = ''+e])
- If passed a WasmAllocError, the message is ingored and the
+ If passed a WasmAllocError, the message is ignored and the
result code is SQLITE_NOMEM. If passed any other Error type,
the result code defaults to SQLITE_ERROR unless the Error
object has a resultCode property, in which case that is used
@@ -662,8 +667,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
);
};
- if(1){/* Bindings for sqlite3_create_collation() */
-
+ if(1){/* Bindings for sqlite3_create_collation[_v2]() */
const __collationContextKey = (argIndex,argv)=>{
return 'argv['+argIndex+']:sqlite3@'+argv[0]+
':'+wasm.cstrToJs(argv[1]).toLowerCase()
@@ -690,15 +694,22 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
Works exactly like C's sqlite3_create_collation_v2() except that:
- 1) It accepts JS functions for its function-pointer arguments,
+ 1) It returns capi.SQLITE_FORMAT if the 3rd argument contains
+ any encoding-related value other than capi.SQLITE_UTF8. No
+ other encodings are supported. As a special case, if the
+ bottom 4 bits of that argument are 0, SQLITE_UTF8 is
+ assumed.
+
+ 2) It accepts JS functions for its function-pointer arguments,
for which it will install WASM-bound proxies. The bindings
are "permanent," in that they will stay in the WASM environment
- until it shuts down unless the client somehow finds and removes
- them.
+ until it shuts down unless the client calls this again with the
+ same collation name and a value of 0 or null for the
+ the function pointer(s).
- 2) It returns capi.SQLITE_FORMAT if the 3rd argument is not
- capi.SQLITE_UTF8. No other encodings are supported. To simplify
- usage, any falsy value of eTextRep is treated as SQLITE_UTF8.
+ For consistency with the C API, it requires the same number of
+ arguments. It returns capi.SQLITE_MISUSE if passed any other
+ argument count.
Returns 0 on success, non-0 on error, in which case the error
state of pDb (of type `sqlite3*` or argument-convertible to it)
@@ -706,9 +717,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
*/
capi.sqlite3_create_collation_v2 = function(pDb,zName,eTextRep,pArg,xCompare,xDestroy){
if(6!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_create_collation_v2', 6);
- else if(!eTextRep){
- eTextRep = capi.SQLITE_UTF8;
- }else if(capi.SQLITE_UTF8!==eTextRep){
+ else if( 0 === (eTextRep & 0xf) ){
+ eTextRep |= capi.SQLITE_UTF8;
+ }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
return __errEncoding(pDb);
}
let rc, pfCompare, pfDestroy;
@@ -777,13 +788,15 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if(1){/* Special-case handling of sqlite3_create_function_v2()
and sqlite3_create_window_function() */
+ /* Maintenance reminder: FuncPtrAdapter is not expressive enough
+ to be able to perform these mappings. */
const sqlite3CreateFunction = wasm.xWrap(
"sqlite3_create_function_v2", "int",
["sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
"int"/*eTextRep*/, "*"/*pApp*/,
"*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/, "*"/*xDestroy*/]
);
- // TODO: reimplement these using FuncPtrAdapter.
+
const sqlite3CreateWindowFunction = wasm.xWrap(
"sqlite3_create_window_function", "int",
["sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
@@ -836,13 +849,13 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
xDestroy: {sig:'v(p)', f:__xDestroy}
});
- const __xWrapFuncs = function(theFuncs, tgtUninst){
+ /* Internal helper for sqlite3_create_function() and friends. */
+ const __xWrapFuncs = function(theKeys, theFuncs, tgtUninst){
const rc = []
- let k;
- for(k in theFuncs){
+ for(const k of theKeys){
let fArg = theFuncs[k];
if('function'===typeof fArg){
- const w = __xMap[k];
+ const w = __xMap[k] || toss3("Internal error in __xWrapFuncs: invalid key:",k);
fArg = wasm.installFunction(w.sig, w.f(fArg));
tgtUninst.push(fArg);
}
@@ -859,18 +872,19 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
xFinal, //void (*xFinal)(sqlite3_context*)
xDestroy //void (*xDestroy)(void*)
){
- if(f.length!==arguments.length){
+ if( f.length!==arguments.length ){
return __dbArgcMismatch(pDb,"sqlite3_create_function_v2",f.length);
- }else if(!eTextRep){
- eTextRep = capi.SQLITE_UTF8;
- }else if(capi.SQLITE_UTF8!==eTextRep){
+ }else if( 0 === (eTextRep & 0xf) ){
+ eTextRep |= capi.SQLITE_UTF8;
+ }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
return __errEncoding(pDb);
}
/* Wrap the callbacks in a WASM-bound functions... */
const uninstall = [/*funcs to uninstall on error*/];
let rc;
try{
- const funcArgs = __xWrapFuncs({xFunc, xStep, xFinal, xDestroy},
+ const funcArgs = __xWrapFuncs(['xFunc','xStep','xFinal','xDestroy'],
+ {xFunc, xStep, xFinal, xDestroy},
uninstall);
rc = sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
pApp, ...funcArgs);
@@ -904,18 +918,19 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
xInverse,//void (*xStep)(sqlite3_context*,int,sqlite3_value**)
xDestroy //void (*xDestroy)(void*)
){
- if(f.length!==arguments.length){
+ if( f.length!==arguments.length ){
return __dbArgcMismatch(pDb,"sqlite3_create_window_function",f.length);
- }else if(!eTextRep){
- eTextRep = capi.SQLITE_UTF8;
- }else if(capi.SQLITE_UTF8!==eTextRep){
+ }else if( 0 === (eTextRep & 0xf) ){
+ eTextRep |= capi.SQLITE_UTF8;
+ }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
return __errEncoding(pDb);
}
/* Wrap the callbacks in a WASM-bound functions... */
const uninstall = [/*funcs to uninstall on error*/];
let rc;
try{
- const funcArgs = __xWrapFuncs({xStep, xFinal, xValue, xInverse, xDestroy},
+ const funcArgs = __xWrapFuncs(['xStep','xFinal','xValue','xInverse','xDestroy'],
+ {xStep, xFinal, xValue, xInverse, xDestroy},
uninstall);
rc = sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep,
pApp, ...funcArgs);
diff --git a/ext/wasm/api/sqlite3-api-oo1.js b/ext/wasm/api/sqlite3-api-oo1.js
index 59ecf56b9..1776cb327 100644
--- a/ext/wasm/api/sqlite3-api-oo1.js
+++ b/ext/wasm/api/sqlite3-api-oo1.js
@@ -1277,28 +1277,13 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
so we have no range checking. */
f._ = {
string: function(stmt, ndx, val, asBlob){
- if(1){
- /* _Hypothetically_ more efficient than the impl in the 'else' block. */
- const stack = wasm.scopedAllocPush();
- try{
- const n = wasm.jstrlen(val);
- const pStr = wasm.scopedAlloc(n);
- wasm.jstrcpy(val, wasm.heap8u(), pStr, n, false);
- const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
- return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_TRANSIENT);
- }finally{
- wasm.scopedAllocPop(stack);
- }
- }else{
- const bytes = wasm.jstrToUintArray(val,false);
- const pStr = wasm.alloc(bytes.length || 1);
- wasm.heap8u().set(bytes.length ? bytes : [0], pStr);
- try{
- const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
- return f(stmt.pointer, ndx, pStr, bytes.length, capi.SQLITE_TRANSIENT);
- }finally{
- wasm.dealloc(pStr);
- }
+ const stack = wasm.scopedAllocPush();
+ try{
+ const [pStr, n] = wasm.scopedAllocCString(val, true);
+ const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
+ return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_TRANSIENT);
+ }finally{
+ wasm.scopedAllocPop(stack);
}
}
};
@@ -1354,7 +1339,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const pBlob = wasm.scopedAlloc(val.byteLength || 1);
wasm.heap8().set(val.byteLength ? val : [0], pBlob)
rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
- capi.SQLITE_TRANSIENT);
+ capi.SQLITE_TRANSIENT);
}finally{
wasm.scopedAllocPop(stack);
}
diff --git a/ext/wasm/api/sqlite3-api-prologue.js b/ext/wasm/api/sqlite3-api-prologue.js
index 94514e477..6c50e99b0 100644
--- a/ext/wasm/api/sqlite3-api-prologue.js
+++ b/ext/wasm/api/sqlite3-api-prologue.js
@@ -425,7 +425,9 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
any encoding other than sqlite3.SQLITE_UTF8. The JS API does not
currently support any other encoding and likely never
will. This function does not replace that argument on its own
- because it may contain other flags.
+ because it may contain other flags. As a special case, if
+ the bottom 4 bits of that argument are 0, SQLITE_UTF8 is
+ assumed.
2) Any of the four final arguments may be either WASM pointers
(assumed to be function pointers) or JS Functions. In the
@@ -433,6 +435,10 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
sqlite3.capi.wasm.installFunction() and that wrapper is passed
on to the native implementation.
+ For consistency with the C API, it requires the same number of
+ arguments. It returns capi.SQLITE_MISUSE if passed any other
+ argument count.
+
The semantics of JS functions are:
xFunc: is passed `(pCtx, ...values)`. Its return value becomes