1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Initial infrastructure for adding virtual table/table-valued function support to WASM.

FossilOrigin-Name: c202d7a0398b9aabc2babba5c4c91a313f32bbf37549d419775642bb4aa3936a
This commit is contained in:
stephan
2022-12-05 05:30:03 +00:00
parent 95ade3bdb9
commit e177447972
7 changed files with 269 additions and 67 deletions

View File

@ -603,13 +603,16 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
} }
wasm.ctype = JSON.parse(wasm.cstringToJs(cJson)); wasm.ctype = JSON.parse(wasm.cstringToJs(cJson));
//console.debug('wasm.ctype length =',wasm.cstrlen(cJson)); //console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
for(const t of ['access', 'blobFinalizers', 'dataTypes', const defineGroups = ['access', 'blobFinalizers', 'dataTypes',
'encodings', 'fcntl', 'flock', 'ioCap', 'encodings', 'fcntl', 'flock', 'ioCap',
'limits', 'limits',
'openFlags', 'prepareFlags', 'resultCodes', 'openFlags', 'prepareFlags', 'resultCodes',
'serialize', 'syncFlags', 'trace', 'udfFlags', 'serialize', 'syncFlags', 'trace', 'udfFlags',
'version' 'version' ];
]){ if(wasm.bigIntEnabled){
defineGroups.push('vtab');
}
for(const t of defineGroups){
for(const e of Object.entries(wasm.ctype[t])){ for(const e of Object.entries(wasm.ctype[t])){
// ^^^ [k,v] there triggers a buggy code transformation via // ^^^ [k,v] there triggers a buggy code transformation via
// one of the Emscripten-driven optimizers. // one of the Emscripten-driven optimizers.
@ -629,19 +632,33 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
capi.sqlite3_js_rc_str = (rc)=>__rcMap[rc]; capi.sqlite3_js_rc_str = (rc)=>__rcMap[rc];
/* Bind all registered C-side structs... */ /* Bind all registered C-side structs... */
const notThese = Object.assign(Object.create(null),{ const notThese = Object.assign(Object.create(null),{
// Structs NOT to register // For each struct to NOT register, map its name to false:
WasmTestStruct: true WasmTestStruct: true,
});
if(!util.isUIThread()){
/* We remove the kvvfs VFS from Worker threads below. */ /* 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){ for(const s of wasm.ctype.structs){
if(!notThese[s.name]){ if(!notThese[s.name]){
capi[s.name] = sqlite3.StructBinder(s); 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"); const pKvvfs = capi.sqlite3_vfs_find("kvvfs");
if( pKvvfs ){/* kvvfs-specific glue */ if( pKvvfs ){/* kvvfs-specific glue */
@ -652,8 +669,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
delete capi.sqlite3_kvvfs_methods; delete capi.sqlite3_kvvfs_methods;
const kvvfsMakeKey = wasm.exports.sqlite3_wasm_kvvfsMakeKeyOnPstack, const kvvfsMakeKey = wasm.exports.sqlite3_wasm_kvvfsMakeKeyOnPstack,
pstack = wasm.pstack, pstack = wasm.pstack;
pAllocRaw = wasm.exports.sqlite3_wasm_pstack_alloc;
const kvvfsStorage = (zClass)=> const kvvfsStorage = (zClass)=>
((115/*=='s'*/===wasm.getMemValue(zClass)) ((115/*=='s'*/===wasm.getMemValue(zClass))

View File

@ -368,7 +368,7 @@ void sqlite3_wasm_test_struct(WasmTestStruct * s){
*/ */
SQLITE_WASM_KEEP SQLITE_WASM_KEEP
const char * sqlite3_wasm_enum_json(void){ 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 int n = 0, nChildren = 0, nStruct = 0
/* output counters for figuring out where commas go */; /* output counters for figuring out where commas go */;
char * zPos = &aBuffer[1] /* skip first byte for now to help protect 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*/; DefInt(SQLITE_ACCESS_READ)/*docs say this is unused*/;
} _DefGroup; } _DefGroup;
#if 0
/* TODO? Authorizer... */
DefGroup(authorizer){
DefInt(SQLITE_DENY);
DefInt(SQLITE_IGNORE);
} _DefGroup;
#endif
DefGroup(blobFinalizers) { DefGroup(blobFinalizers) {
/* SQLITE_STATIC/TRANSIENT need to be handled explicitly as /* SQLITE_STATIC/TRANSIENT need to be handled explicitly as
** integers to avoid casting-related warnings. */ ** integers to avoid casting-related warnings. */
@ -681,7 +689,28 @@ const char * sqlite3_wasm_enum_json(void){
DefStr(SQLITE_VERSION); DefStr(SQLITE_VERSION);
DefStr(SQLITE_SOURCE_ID); DefStr(SQLITE_SOURCE_ID);
} _DefGroup; } _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 DefGroup
#undef DefStr #undef DefStr
#undef DefInt #undef DefInt
@ -793,6 +822,137 @@ const char * sqlite3_wasm_enum_json(void){
} _StructBinder; } _StructBinder;
#undef CurrentStruct #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 #if SQLITE_WASM_TESTS
#define CurrentStruct WasmTestStruct #define CurrentStruct WasmTestStruct
StructBinder { StructBinder {

View File

@ -1081,10 +1081,9 @@ self.WhWasmUtilInstaller = function(target){
// impl for allocMainArgv() and scopedAllocMainArgv(). // impl for allocMainArgv() and scopedAllocMainArgv().
const __allocMainArgv = function(isScoped, list){ const __allocMainArgv = function(isScoped, list){
if(!list.length) toss("Cannot allocate empty array.");
const pList = target[ const pList = target[
isScoped ? 'scopedAlloc' : 'alloc' isScoped ? 'scopedAlloc' : 'alloc'
](list.length * target.ptrSizeof); ]((list.length + 1) * target.ptrSizeof);
let i = 0; let i = 0;
list.forEach((e)=>{ list.forEach((e)=>{
target.setPtrValue(pList + (target.ptrSizeof * i++), target.setPtrValue(pList + (target.ptrSizeof * i++),
@ -1092,26 +1091,33 @@ self.WhWasmUtilInstaller = function(target){
isScoped ? 'scopedAllocCString' : 'allocCString' isScoped ? 'scopedAllocCString' : 'allocCString'
](""+e)); ](""+e));
}); });
target.setPtrValue(pList + (target.ptrSizeof * i), 0);
return pList; return pList;
}; };
/** /**
Creates an array, using scopedAlloc(), suitable for passing to a Creates an array, using scopedAlloc(), suitable for passing to a
C-level main() routine. The input is a collection with a length C-level main() routine. The input is a collection with a length
property and a forEach() method. A block of memory list.length property and a forEach() method. A block of memory
entries long is allocated and each pointer-sized block of that (list.length+1) entries long is allocated and each pointer-sized
memory is populated with a scopedAllocCString() conversion of the block of that memory is populated with a scopedAllocCString()
(""+value) of each element. Returns a pointer to the start of the conversion of the (""+value) of each element, with the exception
list, suitable for passing as the 2nd argument to a C-style that the final entry is a NULL pointer. Returns a pointer to the
main() function. 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. 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); target.scopedAllocMainArgv = (list)=>__allocMainArgv(true, list);
/** /**
Identical to scopedAllocMainArgv() but uses alloc() instead of Identical to scopedAllocMainArgv() but uses alloc() instead of
scopedAllocMainArgv scopedAlloc().
*/ */
target.allocMainArgv = (list)=>__allocMainArgv(false, list); target.allocMainArgv = (list)=>__allocMainArgv(false, list);

View File

@ -121,6 +121,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
at SIG s[0]. Throws for an unknown SIG. */ at SIG s[0]. Throws for an unknown SIG. */
const sigIR = function(s){ const sigIR = function(s){
switch(sigLetter(s)){ switch(sigLetter(s)){
case 'c': case 'C': return 'i8';
case 'i': return 'i32'; case 'i': return 'i32';
case 'p': case 'P': case 's': return ptrIR; case 'p': case 'P': case 's': return ptrIR;
case 'j': return 'i64'; case 'j': return 'i64';
@ -133,6 +134,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
unknown SIG. */ unknown SIG. */
const sigSizeof = function(s){ const sigSizeof = function(s){
switch(sigLetter(s)){ switch(sigLetter(s)){
case 'c': case 'C': return 1;
case 'i': return 4; case 'i': return 4;
case 'p': case 'P': case 's': return ptrSizeof; case 'p': case 'P': case 's': return ptrSizeof;
case 'j': return 8; case 'j': return 8;
@ -168,6 +170,8 @@ self.Jaccwabyt = function StructBinderFactory(config){
break; break;
} }
case 'i': return 'getInt32'; case 'i': return 'getInt32';
case 'c': return 'getInt8';
case 'C': return 'getUint8';
case 'j': return affirmBigIntArray() && 'getBigInt64'; case 'j': return affirmBigIntArray() && 'getBigInt64';
case 'f': return 'getFloat32'; case 'f': return 'getFloat32';
case 'd': return 'getFloat64'; case 'd': return 'getFloat64';
@ -186,6 +190,8 @@ self.Jaccwabyt = function StructBinderFactory(config){
break; break;
} }
case 'i': return 'setInt32'; case 'i': return 'setInt32';
case 'c': return 'setInt8';
case 'C': return 'setUint8';
case 'j': return affirmBigIntArray() && 'setBigInt64'; case 'j': return affirmBigIntArray() && 'setBigInt64';
case 'f': return 'setFloat32'; case 'f': return 'setFloat32';
case 'd': return 'setFloat64'; case 'd': return 'setFloat64';
@ -199,7 +205,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
*/ */
const sigDVSetWrapper = function(s){ const sigDVSetWrapper = function(s){
switch(sigLetter(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 'j': return affirmBigIntArray() && BigInt;
case 'p': case 'P': case 's': case 'p': case 'P': case 's':
switch(ptrSizeof){ switch(ptrSizeof){
@ -361,7 +367,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
framework's native format or in Emscripten format. framework's native format or in Emscripten format.
*/ */
const __memberSignature = function f(obj,memberName,emscriptenFormat=false){ 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); const m = __lookupMember(obj.structInfo, memberName, true);
return emscriptenFormat ? f._(m.signature) : m.signature; return emscriptenFormat ? f._(m.signature) : m.signature;
}; };
@ -570,7 +576,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
/*cache all available getters/setters/set-wrappers for /*cache all available getters/setters/set-wrappers for
direct reuse in each accessor function. */ direct reuse in each accessor function. */
f._ = {getters: {}, setters: {}, sw:{}}; 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'); if(bigIntEnabled) a.push('j');
a.forEach(function(v){ a.forEach(function(v){
//const ir = sigIR(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 f._.sw[v] = sigDVSetWrapper(v) /* BigInt or Number ctor to wrap around values
for conversion */; for conversion */;
}); });
const rxSig1 = /^[ipPsjfd]$/, const rxSig1 = /^[ipPsjfdcC]$/,
rxSig2 = /^[vipPsjfd]\([ipPsjfd]*\)$/; rxSig2 = /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/;
f.sigCheck = function(obj, name, key,sig){ f.sigCheck = function(obj, name, key,sig){
if(Object.prototype.hasOwnProperty.call(obj, key)){ if(Object.prototype.hasOwnProperty.call(obj, key)){
toss(obj.structName,'already has a property named',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); f.sigCheck(ctor.prototype, name, key, descr.signature);
descr.key = key; descr.key = key;
descr.name = name; descr.name = name;
const sizeOf = sigSizeof(descr.signature);
const sigGlyph = sigLetter(descr.signature); const sigGlyph = sigLetter(descr.signature);
const xPropName = sPropName(ctor.prototype.structName,key); const xPropName = sPropName(ctor.prototype.structName,key);
const dbg = ctor.prototype.debugFlags.__flags; const dbg = ctor.prototype.debugFlags.__flags;
@ -610,10 +615,10 @@ self.Jaccwabyt = function StructBinderFactory(config){
prop.get = function(){ prop.get = function(){
if(dbg.getter){ if(dbg.getter){
log("debug.getter:",f._.getters[sigGlyph],"for", sigIR(sigGlyph), 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 = ( 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); )[f._.getters[sigGlyph]](0, isLittleEndian);
if(dbg.getter) log("debug.getter:",xPropName,"result =",rc); if(dbg.getter) log("debug.getter:",xPropName,"result =",rc);
if(rc && isAutoPtrSig(descr.signature)){ if(rc && isAutoPtrSig(descr.signature)){
@ -628,7 +633,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
prop.set = function(v){ prop.set = function(v){
if(dbg.setter){ if(dbg.setter){
log("debug.setter:",f._.setters[sigGlyph],"for", sigIR(sigGlyph), 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){ if(!this.pointer){
toss("Cannot set struct property on disposed instance."); toss("Cannot set struct property on disposed instance.");
@ -644,7 +649,7 @@ self.Jaccwabyt = function StructBinderFactory(config){
toss("Invalid value for pointer-type",xPropName+'.'); 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); )[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."); if(!structName) toss("Struct name is required.");
let lastMember = false; let lastMember = false;
Object.keys(structInfo.members).forEach((k)=>{ Object.keys(structInfo.members).forEach((k)=>{
// Sanity checks of sizeof/offset info...
const m = structInfo.members[k]; const m = structInfo.members[k];
if(!m.sizeof) toss(structName,"member",k,"is missing sizeof."); if(!m.sizeof) toss(structName,"member",k,"is missing sizeof.");
else if(0!==(m.sizeof%4)){ else if(m.sizeof>1){ // offsets of size-1 members may be odd values.
toss(structName,"member",k,"sizeof is not aligned."); if(0!==(m.sizeof%4)){
} console.warn("Invalid struct description =",m,"from",structInfo.members);
else if(0!==(m.offset%4)){ toss(structName,"member",k,"sizeof is not aligned. sizeof="+m.sizeof);
toss(structName,"member",k,"offset is not aligned."); }
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; if(!lastMember || lastMember.offset < m.offset) lastMember = m;
}); });

View File

@ -281,21 +281,29 @@ supported letters are:
signature entry. signature entry.
- **`f`** = `float` (4 bytes) - **`f`** = `float` (4 bytes)
- **`d`** = `double` (8 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. - **`P`** = Like `p` but with extra handling. Described below.
- **`s`** = like `int32` but is a _hint_ that it's a pointer to a string - **`s`** = like `int32` but is a _hint_ that it's a pointer to a
so that _some_ (very limited) contexts may treat it as such, noting string so that _some_ (very limited) contexts may treat it as such,
such algorithms must, for lack of information to the contrary, noting that such algorithms must, for lack of information to the
assume both that the encoding is UTF-8 and that the pointer's member contrary, assume both that the encoding is UTF-8 and that the
is NUL-terminated. If that is _not_ the case for a given string pointer's member is NUL-terminated. If that is _not_ the case for a
member, do not use `s`: use `i` or `p` instead and do any string given string member, do not use `s`: use `i` or `p` instead and do
handling yourself. any string handling yourself.
Noting that: Noting that:
- All of these types are numeric. Attempting to set any struct-bound - All of these types are numeric. Attempting to set any struct-bound
property to a non-numeric value will trigger an exception except in property to a non-numeric value will trigger an exception except in
cases explicitly noted otherwise. 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 > Sidebar: Emscripten's public docs do not mention `p`, but their
generated code includes `p` as an alias for `i`, presumably to mean 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 form `x()`. For function-type signatures, the strings are formulated
such that they can be passed to Emscripten's `addFunction()` after such that they can be passed to Emscripten's `addFunction()` after
stripping out the `(` and `)` characters. For good measure, to match stripping out the `(` and `)` characters. For good measure, to match
the public Emscripten docs, `p` should also be replaced with `i`. In the public Emscripten docs, `p`, `c`, and `C`, should also be replaced
JavaScript that might look like: 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> <a name='step-2-pvsp'></a>

View File

@ -1,5 +1,5 @@
C Improved\squery\splanner\scost\sestimates.\s\sFix\sfor\sticket\s[e8b674241947eb3b]. C Initial\sinfrastructure\sfor\sadding\svirtual\stable/table-valued\sfunction\ssupport\sto\sWASM.
D 2022-12-05T02:52:37.959 D 2022-12-05T05:30:03.152
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 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/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62
F ext/wasm/api/pre-js.c-pp.js b88499dc303c21fc3f55f2c364a0f814f587b60a95784303881169f9e91c1d5f 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-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-oo1.js 91a7d7b9203fb0f031e6ba380a644a7f871e1798b388de399c01ed4087bac9e0
F ext/wasm/api/sqlite3-api-prologue.js 697a5989ad52a9ba7bc60b5436589bd05885ee2201d84c38c5e9af3876af3ba4 F ext/wasm/api/sqlite3-api-prologue.js 697a5989ad52a9ba7bc60b5436589bd05885ee2201d84c38c5e9af3876af3ba4
F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f 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-helper.js 4ad4faf02e1524bf0296be8452c00b5708dce6faf649468d0377e26a0b299263
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 29d6487a26b2fb6a471cde52c37ffee7c27ed6a91914b308c247e0706f454ffb F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 29d6487a26b2fb6a471cde52c37ffee7c27ed6a91914b308c247e0706f454ffb
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9 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-promiser.js 0c7a9826dbf82a5ed4e4f7bf7816e825a52aff253afbf3350431f5773faf0e4b
F ext/wasm/api/sqlite3-worker1.js 1e54ea3d540161bcfb2100368a2fc0cad871a207b8336afee1c445715851ec54 F ext/wasm/api/sqlite3-worker1.js 1e54ea3d540161bcfb2100368a2fc0cad871a207b8336afee1c445715851ec54
F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8 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/SqliteTestUtil.js d8bf97ecb0705a2299765c8fc9e11b1a5ac7f10988bbf375a6558b7ca287067b
F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
F ext/wasm/common/testing.css 35889709547d89a6109ff83b25c11bbc91d8dd43aab8722e428655ca98880a06 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-worker.html a0b58d9caef098a626a1a1db567076fca4245e8d60ba94557ede8684350a81ed
F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508 F ext/wasm/demo-123.html 8c70a412ce386bd3796534257935eb1e3ea5c581e5d5aea0490b8232e570a508
F ext/wasm/demo-123.js ebae30756585bca655b4ab2553ec9236a87c23ad24fc8652115dcedb06d28df6 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/fiddle/index.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2
F ext/wasm/index-dist.html c806b6005145b71d64240606e9c6e0bf56878ee8829c66fe7486cebf34b0e6b1 F ext/wasm/index-dist.html c806b6005145b71d64240606e9c6e0bf56878ee8829c66fe7486cebf34b0e6b1
F ext/wasm/index.html f151b7c7b5cfdc066567d556acd168e769efd4e982286dc5f849a5ee69ecd0ff F ext/wasm/index.html f151b7c7b5cfdc066567d556acd168e769efd4e982286dc5f849a5ee69ecd0ff
F ext/wasm/jaccwabyt/jaccwabyt.js 95f573de1826474c9605dda620ee622fcb1673ae74f191eb324c0853aa4dcb66 F ext/wasm/jaccwabyt/jaccwabyt.js 7c41784c442aa67f0e86e7c14aa51b3a28e3b21eb579c71c16af3c988fbf966f
F ext/wasm/jaccwabyt/jaccwabyt.md 9aa6951b529a8b29f578ec8f0355713c39584c92cf1708f63ba0cf917cb5b68e F ext/wasm/jaccwabyt/jaccwabyt.md 50df3ccb7a773634000496a2ccb805dd25cf8cd963696a7deec3209a68c6093b
F ext/wasm/module-symbols.html 980680c8acfa3c8ae6a5aa223512d1b8e78040ced20f8ba2c382129bc73ec028 F ext/wasm/module-symbols.html 980680c8acfa3c8ae6a5aa223512d1b8e78040ced20f8ba2c382129bc73ec028
F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06 F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06
F ext/wasm/scratchpad-wasmfs-main.js 4c140457f4d6da9d646a49addd91edb6e9ad1643c6c48e3258b5bce24725dc18 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.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P cefc032473ac5ad244c0b6402c541b2f76c0c65a041bda03bfbe7c0e2c11fac2 df3818997b822743ac407dde45c5fd75845ca40f461e31350d86963dffec6cd6 P 1b779afa3ed2f35a110e460fc6ed13cba744db85b9924149ab028b100d1e1e12
R 3c93957174c9bb89beba8a6d7c9fdaab R b429259a443dd7b0ac8ceede26128588
T +closed df3818997b822743ac407dde45c5fd75845ca40f461e31350d86963dffec6cd6 T *branch * wasm-vtab
U drh T *sym-wasm-vtab *
Z 2d83b2d52ce6d0637e1b84504b86ac00 T -sym-trunk * Cancelled\sby\sbranch.
U stephan
Z bd980b10d448d088ee0cbb8238fc2a43
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
1b779afa3ed2f35a110e460fc6ed13cba744db85b9924149ab028b100d1e1e12 c202d7a0398b9aabc2babba5c4c91a313f32bbf37549d419775642bb4aa3936a