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:
@ -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))
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
});
|
});
|
||||||
|
@ -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>
|
||||||
|
26
manifest
26
manifest
@ -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.
|
||||||
|
@ -1 +1 @@
|
|||||||
1b779afa3ed2f35a110e460fc6ed13cba744db85b9924149ab028b100d1e1e12
|
c202d7a0398b9aabc2babba5c4c91a313f32bbf37549d419775642bb4aa3936a
|
Reference in New Issue
Block a user