mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Merge trunk into wasm-session-api branch.
FossilOrigin-Name: 7f8f1acd82be7dc2eb2147d96299b1b443e86774dfe0b0a8d32669a0500fc9c6
This commit is contained in:
@ -32,6 +32,7 @@ _sqlite3_column_value
|
|||||||
_sqlite3_compileoption_get
|
_sqlite3_compileoption_get
|
||||||
_sqlite3_compileoption_used
|
_sqlite3_compileoption_used
|
||||||
_sqlite3_complete
|
_sqlite3_complete
|
||||||
|
_sqlite3_context_db_handle
|
||||||
_sqlite3_create_collation
|
_sqlite3_create_collation
|
||||||
_sqlite3_create_collation_v2
|
_sqlite3_create_collation_v2
|
||||||
_sqlite3_create_function
|
_sqlite3_create_function
|
||||||
|
@ -24,6 +24,33 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
self.WhWasmUtilInstaller(wasm);
|
self.WhWasmUtilInstaller(wasm);
|
||||||
delete self.WhWasmUtilInstaller;
|
delete self.WhWasmUtilInstaller;
|
||||||
|
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
Find a mapping for SQLITE_WASM_DEALLOC, which the API
|
||||||
|
guarantees is a WASM pointer to the same underlying function as
|
||||||
|
wasm.dealloc() (noting that wasm.dealloc() is permitted to be a
|
||||||
|
JS wrapper around the WASM function). There is unfortunately no
|
||||||
|
O(1) algorithm for finding this pointer: we have to walk the
|
||||||
|
WASM indirect function table to find it. However, experience
|
||||||
|
indicates that that particular function is always very close to
|
||||||
|
the front of the table (it's been entry #3 in all relevant
|
||||||
|
tests).
|
||||||
|
*/
|
||||||
|
const dealloc = wasm.exports[sqlite3.config.deallocExportName];
|
||||||
|
const nFunc = wasm.functionTable().length;
|
||||||
|
let i;
|
||||||
|
for(i = 0; i < nFunc; ++i){
|
||||||
|
const e = wasm.functionEntry(i);
|
||||||
|
if(dealloc === e){
|
||||||
|
capi.SQLITE_WASM_DEALLOC = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(dealloc !== wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)){
|
||||||
|
toss("Internal error: cannot find function pointer for SQLITE_WASM_DEALLOC.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Signatures for the WASM-exported C-side functions. Each entry
|
Signatures for the WASM-exported C-side functions. Each entry
|
||||||
is an array with 2+ elements:
|
is an array with 2+ elements:
|
||||||
@ -42,10 +69,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
wasm.bindingSignatures = [
|
wasm.bindingSignatures = [
|
||||||
// Please keep these sorted by function name!
|
// Please keep these sorted by function name!
|
||||||
["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
|
["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
|
||||||
["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*"
|
/* sqlite3_bind_blob() and sqlite3_bind_text() have hand-written
|
||||||
/* TODO: we should arguably write a custom wrapper which knows
|
bindings to permit more flexible inputs. */
|
||||||
how to handle Blob, TypedArrays, and JS strings. */
|
|
||||||
],
|
|
||||||
["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
|
["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
|
||||||
["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
|
["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
|
||||||
["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
|
["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
|
||||||
@ -53,19 +78,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
|
["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
|
||||||
["sqlite3_bind_pointer", "int",
|
["sqlite3_bind_pointer", "int",
|
||||||
"sqlite3_stmt*", "int", "*", "string:static", "*"],
|
"sqlite3_stmt*", "int", "*", "string:static", "*"],
|
||||||
["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
|
|
||||||
part is the final argument (text destructor). */
|
|
||||||
],
|
|
||||||
["sqlite3_busy_handler","int", [
|
["sqlite3_busy_handler","int", [
|
||||||
"sqlite3*",
|
"sqlite3*",
|
||||||
new wasm.xWrap.FuncPtrAdapter({
|
new wasm.xWrap.FuncPtrAdapter({
|
||||||
name: 'sqlite3_busy_handler',
|
|
||||||
signature: 'i(pi)',
|
signature: 'i(pi)',
|
||||||
bindScope: 'context',
|
contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
|
||||||
contextKey: (argIndex,argv)=>'sqlite3@'+argv[0]
|
|
||||||
}),
|
}),
|
||||||
"*"
|
"*"
|
||||||
]],
|
]],
|
||||||
@ -86,6 +103,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
["sqlite3_compileoption_get", "string", "int"],
|
["sqlite3_compileoption_get", "string", "int"],
|
||||||
["sqlite3_compileoption_used", "int", "string"],
|
["sqlite3_compileoption_used", "int", "string"],
|
||||||
["sqlite3_complete", "int", "string:flexible"],
|
["sqlite3_complete", "int", "string:flexible"],
|
||||||
|
["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"],
|
||||||
|
|
||||||
/* sqlite3_create_function(), sqlite3_create_function_v2(), and
|
/* sqlite3_create_function(), sqlite3_create_function_v2(), and
|
||||||
sqlite3_create_window_function() use hand-written bindings to
|
sqlite3_create_window_function() use hand-written bindings to
|
||||||
simplify handling of their function-type arguments. */
|
simplify handling of their function-type arguments. */
|
||||||
@ -137,18 +156,14 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
for those, depending on how their SQL argument is provided. */
|
for those, depending on how their SQL argument is provided. */
|
||||||
/* sqlite3_randomness() uses a hand-written wrapper to extend
|
/* sqlite3_randomness() uses a hand-written wrapper to extend
|
||||||
the range of supported argument types. */
|
the range of supported argument types. */
|
||||||
[
|
["sqlite3_progress_handler", undefined, [
|
||||||
"sqlite3_progress_handler", undefined, [
|
"sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({
|
||||||
"sqlite3*", "int",
|
|
||||||
new wasm.xWrap.FuncPtrAdapter({
|
|
||||||
name: 'xProgressHandler',
|
name: 'xProgressHandler',
|
||||||
signature: 'i(p)',
|
signature: 'i(p)',
|
||||||
bindScope: 'context',
|
bindScope: 'context',
|
||||||
contextKey: (argIndex,argv)=>'sqlite3@'+argv[0]
|
contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
|
||||||
}),
|
}), "*"
|
||||||
"*"
|
]],
|
||||||
]
|
|
||||||
],
|
|
||||||
["sqlite3_realloc", "*","*","int"],
|
["sqlite3_realloc", "*","*","int"],
|
||||||
["sqlite3_reset", "int", "sqlite3_stmt*"],
|
["sqlite3_reset", "int", "sqlite3_stmt*"],
|
||||||
["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"],
|
["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"],
|
||||||
@ -164,7 +179,34 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"],
|
["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"],
|
||||||
["sqlite3_result_text", undefined, "sqlite3_context*", "string", "int", "*"],
|
["sqlite3_result_text", undefined, "sqlite3_context*", "string", "int", "*"],
|
||||||
["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"],
|
["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"],
|
||||||
["sqlite3_set_auxdata", undefined, "sqlite3_context*", "int", "*", "*"/* => v(*) */],
|
["sqlite3_set_authorizer", "int", [
|
||||||
|
"sqlite3*",
|
||||||
|
new wasm.xWrap.FuncPtrAdapter({
|
||||||
|
name: "sqlite3_set_authorizer::xAuth",
|
||||||
|
signature: "i(pi"+"ssss)",
|
||||||
|
contextKey: (argv, argIndex)=>argv[0/*(sqlite3*)*/],
|
||||||
|
callProxy: (callback)=>{
|
||||||
|
return (pV, iCode, s0, s1, s2, s3)=>{
|
||||||
|
try{
|
||||||
|
s0 = s0 && wasm.cstrToJs(s0); s1 = s1 && wasm.cstrToJs(s1);
|
||||||
|
s2 = s2 && wasm.cstrToJs(s2); s3 = s3 && wasm.cstrToJs(s3);
|
||||||
|
return callback(pV, iCode, s0, s1, s2, s3) || 0;
|
||||||
|
}catch(e){
|
||||||
|
return e.resultCode || capi.SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
"*"/*pUserData*/
|
||||||
|
]],
|
||||||
|
["sqlite3_set_auxdata", undefined, [
|
||||||
|
"sqlite3_context*", "int", "*",
|
||||||
|
new wasm.xWrap.FuncPtrAdapter({
|
||||||
|
name: 'xDestroyAuxData',
|
||||||
|
signature: 'v(*)',
|
||||||
|
contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
|
||||||
|
})
|
||||||
|
]],
|
||||||
["sqlite3_shutdown", undefined],
|
["sqlite3_shutdown", undefined],
|
||||||
["sqlite3_sourceid", "string"],
|
["sqlite3_sourceid", "string"],
|
||||||
["sqlite3_sql", "string", "sqlite3_stmt*"],
|
["sqlite3_sql", "string", "sqlite3_stmt*"],
|
||||||
@ -181,12 +223,15 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
"sqlite3*", "string", "string", "string",
|
"sqlite3*", "string", "string", "string",
|
||||||
"**", "**", "*", "*", "*"],
|
"**", "**", "*", "*", "*"],
|
||||||
["sqlite3_total_changes", "int", "sqlite3*"],
|
["sqlite3_total_changes", "int", "sqlite3*"],
|
||||||
["sqlite3_trace_v2", "int", "sqlite3*", "int",
|
["sqlite3_trace_v2", "int", [
|
||||||
|
"sqlite3*", "int",
|
||||||
new wasm.xWrap.FuncPtrAdapter({
|
new wasm.xWrap.FuncPtrAdapter({
|
||||||
name: 'sqlite3_trace_v2::callback',
|
name: 'sqlite3_trace_v2::callback',
|
||||||
signature: 'i(ippp)',
|
signature: 'i(ippp)',
|
||||||
contextKey: (argIndex, argv)=>'sqlite3@'+argv[0]
|
contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
|
||||||
}), "*"],
|
}),
|
||||||
|
"*"
|
||||||
|
]],
|
||||||
["sqlite3_txn_state", "int", ["sqlite3*","string"]],
|
["sqlite3_txn_state", "int", ["sqlite3*","string"]],
|
||||||
/* Note that sqlite3_uri_...() have very specific requirements for
|
/* Note that sqlite3_uri_...() have very specific requirements for
|
||||||
their first C-string arguments, so we cannot perform any value
|
their first C-string arguments, so we cannot perform any value
|
||||||
@ -252,8 +297,6 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
["sqlite3_result_int64", undefined, "*", "i64"],
|
["sqlite3_result_int64", undefined, "*", "i64"],
|
||||||
["sqlite3_result_zeroblob64", "int", "*", "i64"],
|
["sqlite3_result_zeroblob64", "int", "*", "i64"],
|
||||||
["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"],
|
["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"],
|
||||||
/* sqlite3_set_authorizer() requires a hand-written binding for
|
|
||||||
string conversions, so is defined elsewhere. */
|
|
||||||
["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]],
|
["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]],
|
||||||
["sqlite3_status64", "int", "int", "*", "*", "int"],
|
["sqlite3_status64", "int", "int", "*", "*", "int"],
|
||||||
["sqlite3_total_changes64", "i64", ["sqlite3*"]],
|
["sqlite3_total_changes64", "i64", ["sqlite3*"]],
|
||||||
@ -667,28 +710,24 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(1){/* Bindings for sqlite3_create_collation[_v2]() */
|
{/* Bindings for sqlite3_create_collation[_v2]() */
|
||||||
const __collationContextKey = (argIndex,argv)=>{
|
// contextKey() impl for wasm.xWrap.FuncPtrAdapter
|
||||||
return 'argv['+argIndex+']:sqlite3@'+argv[0]+
|
const contextKey = (argv,argIndex)=>{
|
||||||
':'+wasm.cstrToJs(argv[1]).toLowerCase()
|
return 'argv['+argIndex+']:'+argv[0/* sqlite3* */]+
|
||||||
|
':'+wasm.cstrToJs(argv[1/* collation name */]).toLowerCase()
|
||||||
};
|
};
|
||||||
const __ccv2 = wasm.xWrap(
|
const __sqlite3CreateCollationV2 = wasm.xWrap(
|
||||||
'sqlite3_create_collation_v2', 'int',
|
'sqlite3_create_collation_v2', 'int', [
|
||||||
'sqlite3*','string','int','*',
|
'sqlite3*', 'string', 'int', '*',
|
||||||
new wasm.xWrap.FuncPtrAdapter({
|
new wasm.xWrap.FuncPtrAdapter({
|
||||||
/* int(*xCompare)(void*,int,const void*,int,const void*) */
|
/* int(*xCompare)(void*,int,const void*,int,const void*) */
|
||||||
name: 'sqlite3_create_collation_v2::xCompare',
|
name: 'xCompare', signature: 'i(pipip)', contextKey
|
||||||
signature: 'i(pipip)',
|
|
||||||
bindScope: 'context',
|
|
||||||
contextKey: __collationContextKey
|
|
||||||
}),
|
}),
|
||||||
new wasm.xWrap.FuncPtrAdapter({
|
new wasm.xWrap.FuncPtrAdapter({
|
||||||
/* void(*xDestroy(void*) */
|
/* void(*xDestroy(void*) */
|
||||||
name: 'sqlite3_create_collation_v2::xDestroy',
|
name: 'xDestroy', signature: 'v(p)', contextKey
|
||||||
signature: 'v(p)',
|
|
||||||
bindScope: 'context',
|
|
||||||
contextKey: __collationContextKey
|
|
||||||
})
|
})
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -722,13 +761,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
}else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
|
}else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
|
||||||
return __errEncoding(pDb);
|
return __errEncoding(pDb);
|
||||||
}
|
}
|
||||||
let rc, pfCompare, pfDestroy;
|
|
||||||
try{
|
try{
|
||||||
rc = __ccv2(pDb, zName, eTextRep, pArg, xCompare, xDestroy);
|
return __sqlite3CreateCollationV2(pDb, zName, eTextRep, pArg, xCompare, xDestroy);
|
||||||
}catch(e){
|
}catch(e){
|
||||||
rc = util.sqlite3_wasm_db_error(pDb, e);
|
return util.sqlite3_wasm_db_error(pDb, e);
|
||||||
}
|
}
|
||||||
return rc;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
capi.sqlite3_create_collation = (pDb,zName,eTextRep,pArg,xCompare)=>{
|
capi.sqlite3_create_collation = (pDb,zName,eTextRep,pArg,xCompare)=>{
|
||||||
@ -739,7 +776,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
|
|
||||||
}/*sqlite3_create_collation() and friends*/
|
}/*sqlite3_create_collation() and friends*/
|
||||||
|
|
||||||
if(1){/* Special-case handling of sqlite3_exec() */
|
{/* Special-case handling of sqlite3_exec() */
|
||||||
const __exec = wasm.xWrap("sqlite3_exec", "int",
|
const __exec = wasm.xWrap("sqlite3_exec", "int",
|
||||||
["sqlite3*", "string:flexible",
|
["sqlite3*", "string:flexible",
|
||||||
new wasm.xWrap.FuncPtrAdapter({
|
new wasm.xWrap.FuncPtrAdapter({
|
||||||
@ -755,25 +792,21 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
}
|
}
|
||||||
/* Wrap the callback in a WASM-bound function and convert the callback's
|
/* Wrap the callback in a WASM-bound function and convert the callback's
|
||||||
`(char**)` arguments to arrays of strings... */
|
`(char**)` arguments to arrays of strings... */
|
||||||
|
let aNames;
|
||||||
const cbwrap = function(pVoid, nCols, pColVals, pColNames){
|
const cbwrap = function(pVoid, nCols, pColVals, pColNames){
|
||||||
let rc = capi.SQLITE_ERROR;
|
|
||||||
try {
|
try {
|
||||||
let aVals = [], aNames = [], i = 0, offset = 0;
|
const aVals = wasm.cArgvToJs(nCols, pColVals);
|
||||||
for( ; i < nCols; offset += (wasm.ptrSizeof * ++i) ){
|
if(!aNames) aNames = wasm.cArgvToJs(nCols, pColNames);
|
||||||
aVals.push( wasm.cstrToJs(wasm.peekPtr(pColVals + offset)) );
|
return callback(aVals, aNames) | 0;
|
||||||
aNames.push( wasm.cstrToJs(wasm.peekPtr(pColNames + offset)) );
|
|
||||||
}
|
|
||||||
rc = callback(pVoid, nCols, aVals, aNames) | 0;
|
|
||||||
/* The first 2 args of the callback are useless for JS but
|
|
||||||
we want the JS mapping of the C API to be as close to the
|
|
||||||
C API as possible. */
|
|
||||||
}catch(e){
|
}catch(e){
|
||||||
/* If we set the db error state here, the higher-level exec() call
|
/* If we set the db error state here, the higher-level
|
||||||
replaces it with its own, so we have no way of reporting the
|
exec() call replaces it with its own, so we have no way
|
||||||
exception message except the console. We must not propagate
|
of reporting the exception message except the console. We
|
||||||
exceptions through the C API. */
|
must not propagate exceptions through the C API. Though
|
||||||
|
we make an effort to report OOM here, sqlite3_exec()
|
||||||
|
translates that into SQLITE_ABORT as well. */
|
||||||
|
return e.resultCode || capi.SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
return rc;
|
|
||||||
};
|
};
|
||||||
let rc;
|
let rc;
|
||||||
try{
|
try{
|
||||||
@ -786,27 +819,46 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
};
|
};
|
||||||
}/*sqlite3_exec() proxy*/;
|
}/*sqlite3_exec() proxy*/;
|
||||||
|
|
||||||
if(1){/* Special-case handling of sqlite3_create_function_v2()
|
{/* Special-case handling of sqlite3_create_function_v2()
|
||||||
and sqlite3_create_window_function() */
|
and sqlite3_create_window_function(). */
|
||||||
/* Maintenance reminder: FuncPtrAdapter is not expressive enough
|
/**
|
||||||
to be able to perform these mappings. */
|
FuncPtrAdapter for contextKey() for sqlite3_create_function().
|
||||||
const sqlite3CreateFunction = wasm.xWrap(
|
*/
|
||||||
"sqlite3_create_function_v2", "int",
|
const contextKey = function(argv,argIndex){
|
||||||
["sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
|
return (
|
||||||
"int"/*eTextRep*/, "*"/*pApp*/,
|
argv[0/* sqlite3* */]
|
||||||
"*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/, "*"/*xDestroy*/]
|
+':'+argIndex
|
||||||
);
|
+':'+wasm.cstrToJs(argv[1]).toLowerCase()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
const sqlite3CreateWindowFunction = wasm.xWrap(
|
/**
|
||||||
"sqlite3_create_window_function", "int",
|
JS proxies for the various sqlite3_create[_window]_function()
|
||||||
["sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
|
callbacks, structured in a form usable by wasm.xWrap.FuncPtrAdapter.
|
||||||
"int"/*eTextRep*/, "*"/*pApp*/,
|
*/
|
||||||
"*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/,
|
const __cfProxy = Object.assign(Object.create(null), {
|
||||||
"*"/*xInverse*/, "*"/*xDestroy*/]
|
xInverseAndStep: {
|
||||||
);
|
signature:'v(pip)', contextKey,
|
||||||
|
callProxy: (callback)=>{
|
||||||
const __xFunc = function(callback){
|
return (pCtx, argc, pArgv)=>{
|
||||||
return function(pCtx, argc, pArgv){
|
try{ callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) }
|
||||||
|
catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xFinalAndValue: {
|
||||||
|
signature:'v(p)', contextKey,
|
||||||
|
callProxy: (callback)=>{
|
||||||
|
return (pCtx)=>{
|
||||||
|
try{ capi.sqlite3_result_js(pCtx, callback(pCtx)) }
|
||||||
|
catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xFunc: {
|
||||||
|
signature:'v(pip)', contextKey,
|
||||||
|
callProxy: (callback)=>{
|
||||||
|
return (pCtx, argc, pArgv)=>{
|
||||||
try{
|
try{
|
||||||
capi.sqlite3_result_js(
|
capi.sqlite3_result_js(
|
||||||
pCtx,
|
pCtx,
|
||||||
@ -817,52 +869,42 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
capi.sqlite3_result_error_js(pCtx, e);
|
capi.sqlite3_result_error_js(pCtx, e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
},
|
||||||
const __xInverseAndStep = function(callback){
|
xDestroy: {
|
||||||
return function(pCtx, argc, pArgv){
|
signature:'v(p)', contextKey,
|
||||||
try{ callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) }
|
//Arguable: a well-behaved destructor doesn't require a proxy.
|
||||||
catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
|
callProxy: (callback)=>{
|
||||||
};
|
return (pVoid)=>{
|
||||||
};
|
|
||||||
|
|
||||||
const __xFinalAndValue = function(callback){
|
|
||||||
return function(pCtx){
|
|
||||||
try{ capi.sqlite3_result_js(pCtx, callback(pCtx)) }
|
|
||||||
catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const __xDestroy = function(callback){
|
|
||||||
return function(pVoid){
|
|
||||||
try{ callback(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}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* Internal helper for sqlite3_create_function() and friends. */
|
|
||||||
const __xWrapFuncs = function(theKeys, theFuncs, tgtUninst){
|
|
||||||
const rc = []
|
|
||||||
for(const k of theKeys){
|
|
||||||
let fArg = theFuncs[k];
|
|
||||||
if('function'===typeof fArg){
|
|
||||||
const w = __xMap[k] || toss3("Internal error in __xWrapFuncs: invalid key:",k);
|
|
||||||
fArg = wasm.installFunction(w.sig, w.f(fArg));
|
|
||||||
tgtUninst.push(fArg);
|
|
||||||
}
|
}
|
||||||
rc.push(fArg);
|
|
||||||
}
|
}
|
||||||
return rc;
|
})/*__cfProxy*/;
|
||||||
};
|
|
||||||
|
const __sqlite3CreateFunction = wasm.xWrap(
|
||||||
|
"sqlite3_create_function_v2", "int", [
|
||||||
|
"sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
|
||||||
|
"int"/*eTextRep*/, "*"/*pApp*/,
|
||||||
|
new wasm.xWrap.FuncPtrAdapter({name: 'xFunc', ...__cfProxy.xFunc}),
|
||||||
|
new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}),
|
||||||
|
new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}),
|
||||||
|
new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy})
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
const __sqlite3CreateWindowFunction = wasm.xWrap(
|
||||||
|
"sqlite3_create_window_function", "int", [
|
||||||
|
"sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
|
||||||
|
"int"/*eTextRep*/, "*"/*pApp*/,
|
||||||
|
new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}),
|
||||||
|
new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}),
|
||||||
|
new wasm.xWrap.FuncPtrAdapter({name: 'xValue', ...__cfProxy.xFinalAndValue}),
|
||||||
|
new wasm.xWrap.FuncPtrAdapter({name: 'xInverse', ...__cfProxy.xInverseAndStep}),
|
||||||
|
new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy})
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
/* Documented in the api object's initializer. */
|
/* Documented in the api object's initializer. */
|
||||||
capi.sqlite3_create_function_v2 = function f(
|
capi.sqlite3_create_function_v2 = function f(
|
||||||
@ -879,26 +921,16 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
}else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
|
}else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
|
||||||
return __errEncoding(pDb);
|
return __errEncoding(pDb);
|
||||||
}
|
}
|
||||||
/* Wrap the callbacks in a WASM-bound functions... */
|
|
||||||
const uninstall = [/*funcs to uninstall on error*/];
|
|
||||||
let rc;
|
|
||||||
try{
|
try{
|
||||||
const funcArgs = __xWrapFuncs(['xFunc','xStep','xFinal','xDestroy'],
|
return __sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
|
||||||
{xFunc, xStep, xFinal, xDestroy},
|
pApp, xFunc, xStep, xFinal, xDestroy);
|
||||||
uninstall);
|
|
||||||
rc = sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
|
|
||||||
pApp, ...funcArgs);
|
|
||||||
}catch(e){
|
}catch(e){
|
||||||
console.error("sqlite3_create_function_v2() setup threw:",e);
|
console.error("sqlite3_create_function_v2() setup threw:",e);
|
||||||
for(let v of uninstall){
|
return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
|
||||||
wasm.uninstallFunction(v);
|
|
||||||
}
|
}
|
||||||
rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR,
|
|
||||||
"Creation of UDF threw: "+e.message);
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Documented in the api object's initializer. */
|
||||||
capi.sqlite3_create_function = function f(
|
capi.sqlite3_create_function = function f(
|
||||||
pDb, funcName, nArg, eTextRep, pApp,
|
pDb, funcName, nArg, eTextRep, pApp,
|
||||||
xFunc, xStep, xFinal
|
xFunc, xStep, xFinal
|
||||||
@ -914,8 +946,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
pDb, funcName, nArg, eTextRep, pApp,
|
pDb, funcName, nArg, eTextRep, pApp,
|
||||||
xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
|
xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
|
||||||
xFinal, //void (*xFinal)(sqlite3_context*)
|
xFinal, //void (*xFinal)(sqlite3_context*)
|
||||||
xValue, //void (*xFinal)(sqlite3_context*)
|
xValue, //void (*xValue)(sqlite3_context*)
|
||||||
xInverse,//void (*xStep)(sqlite3_context*,int,sqlite3_value**)
|
xInverse,//void (*xInverse)(sqlite3_context*,int,sqlite3_value**)
|
||||||
xDestroy //void (*xDestroy)(void*)
|
xDestroy //void (*xDestroy)(void*)
|
||||||
){
|
){
|
||||||
if( f.length!==arguments.length ){
|
if( f.length!==arguments.length ){
|
||||||
@ -925,24 +957,14 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
}else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
|
}else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
|
||||||
return __errEncoding(pDb);
|
return __errEncoding(pDb);
|
||||||
}
|
}
|
||||||
/* Wrap the callbacks in a WASM-bound functions... */
|
|
||||||
const uninstall = [/*funcs to uninstall on error*/];
|
|
||||||
let rc;
|
|
||||||
try{
|
try{
|
||||||
const funcArgs = __xWrapFuncs(['xStep','xFinal','xValue','xInverse','xDestroy'],
|
return __sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep,
|
||||||
{xStep, xFinal, xValue, xInverse, xDestroy},
|
pApp, xStep, xFinal, xValue,
|
||||||
uninstall);
|
xInverse, xDestroy);
|
||||||
rc = sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep,
|
|
||||||
pApp, ...funcArgs);
|
|
||||||
}catch(e){
|
}catch(e){
|
||||||
console.error("sqlite3_create_window_function() setup threw:",e);
|
console.error("sqlite3_create_window_function() setup threw:",e);
|
||||||
for(let v of uninstall){
|
return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
|
||||||
wasm.uninstallFunction(v);
|
|
||||||
}
|
}
|
||||||
rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR,
|
|
||||||
"Creation of UDF threw: "+e.message);
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
A _deprecated_ alias for capi.sqlite3_result_js() which
|
A _deprecated_ alias for capi.sqlite3_result_js() which
|
||||||
@ -972,6 +994,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
|
|
||||||
if(1){/* Special-case handling of sqlite3_prepare_v2() and
|
if(1){/* Special-case handling of sqlite3_prepare_v2() and
|
||||||
sqlite3_prepare_v3() */
|
sqlite3_prepare_v3() */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Helper for string:flexible conversions which require a
|
Helper for string:flexible conversions which require a
|
||||||
byte-length counterpart argument. Passed a value and its
|
byte-length counterpart argument. Passed a value and its
|
||||||
@ -995,18 +1018,18 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
/**
|
/**
|
||||||
Scope-local holder of the two impls of sqlite3_prepare_v2/v3().
|
Scope-local holder of the two impls of sqlite3_prepare_v2/v3().
|
||||||
*/
|
*/
|
||||||
const __prepare = Object.create(null);
|
const __prepare = {
|
||||||
/**
|
/**
|
||||||
This binding expects a JS string as its 2nd argument and
|
This binding expects a JS string as its 2nd argument and
|
||||||
null as its final argument. In order to compile multiple
|
null as its final argument. In order to compile multiple
|
||||||
statements from a single string, the "full" impl (see
|
statements from a single string, the "full" impl (see
|
||||||
below) must be used.
|
below) must be used.
|
||||||
*/
|
*/
|
||||||
__prepare.basic = wasm.xWrap('sqlite3_prepare_v3',
|
basic: wasm.xWrap('sqlite3_prepare_v3',
|
||||||
"int", ["sqlite3*", "string",
|
"int", ["sqlite3*", "string",
|
||||||
"int"/*ignored for this impl!*/,
|
"int"/*ignored for this impl!*/,
|
||||||
"int", "**",
|
"int", "**",
|
||||||
"**"/*MUST be 0 or null or undefined!*/]);
|
"**"/*MUST be 0 or null or undefined!*/]),
|
||||||
/**
|
/**
|
||||||
Impl which requires that the 2nd argument be a pointer
|
Impl which requires that the 2nd argument be a pointer
|
||||||
to the SQL string, instead of being converted to a
|
to the SQL string, instead of being converted to a
|
||||||
@ -1018,9 +1041,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
named sqlite3_prepare_v2() is sufficient and easier to
|
named sqlite3_prepare_v2() is sufficient and easier to
|
||||||
use because it doesn't require dealing with pointers.
|
use because it doesn't require dealing with pointers.
|
||||||
*/
|
*/
|
||||||
__prepare.full = wasm.xWrap('sqlite3_prepare_v3',
|
full: wasm.xWrap('sqlite3_prepare_v3',
|
||||||
"int", ["sqlite3*", "*", "int", "int",
|
"int", ["sqlite3*", "*", "int", "int",
|
||||||
"**", "**"]);
|
"**", "**"])
|
||||||
|
};
|
||||||
|
|
||||||
/* Documented in the capi object's initializer. */
|
/* Documented in the capi object's initializer. */
|
||||||
capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){
|
capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){
|
||||||
@ -1045,38 +1069,86 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail)
|
? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail)
|
||||||
: __dbArgcMismatch(pDb,"sqlite3_prepare_v2",f.length);
|
: __dbArgcMismatch(pDb,"sqlite3_prepare_v2",f.length);
|
||||||
};
|
};
|
||||||
}/*sqlite3_prepare_v2/v3()*/;
|
|
||||||
|
|
||||||
{/* sqlite3_set_authorizer() */
|
}/*sqlite3_prepare_v2/v3()*/
|
||||||
const __ssa = wasm.xWrap("sqlite3_set_authorizer", 'int', [
|
|
||||||
"sqlite3*",
|
{/*sqlite3_bind_text/blob()*/
|
||||||
new wasm.xWrap.FuncPtrAdapter({
|
const __bindText = wasm.xWrap("sqlite3_bind_text", "int", [
|
||||||
name: "sqlite3_set_authorizer::xAuth",
|
"sqlite3_stmt*", "int", "string", "int", "*"
|
||||||
signature: "i(pi"+"ssss)",
|
|
||||||
contextKey: (argIndex, argv)=>argv[0/*(sqlite3*)*/]
|
|
||||||
}),
|
|
||||||
"*"
|
|
||||||
]);
|
]);
|
||||||
capi.sqlite3_set_authorizer = function(pDb, xAuth, pUserData){
|
const __bindBlob = wasm.xWrap("sqlite3_bind_blob", "int", [
|
||||||
if(3!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_set_authorizer', 3);
|
"sqlite3_stmt*", "int", "*", "int", "*"
|
||||||
if(xAuth instanceof Function){
|
]);
|
||||||
const xProxy = xAuth;
|
|
||||||
/* Create a proxy which will receive the C-strings from WASM
|
/** Documented in the capi object's initializer. */
|
||||||
and convert them to JS strings for the client-supplied
|
capi.sqlite3_bind_text = function f(pStmt, iCol, text, nText, xDestroy){
|
||||||
function. */
|
if(f.length!==arguments.length){
|
||||||
xAuth = function(pV, iCode, s0, s1, s2, s3){
|
return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt),
|
||||||
|
"sqlite3_bind_text", f.length);
|
||||||
|
}else if(wasm.isPtr(text) || null===text){
|
||||||
|
return __bindText(pStmt, iCol, text, nText, xDestroy);
|
||||||
|
}else if(text instanceof ArrayBuffer){
|
||||||
|
text = new Uint8Array(text);
|
||||||
|
}else if(Array.isArray(pMem)){
|
||||||
|
text = pMem.join('');
|
||||||
|
}
|
||||||
|
let p, n;
|
||||||
try{
|
try{
|
||||||
s0 = s0 && wasm.cstrToJs(s0); s1 = s1 && wasm.cstrToJs(s1);
|
if(util.isSQLableTypedArray(text)){
|
||||||
s2 = s2 && wasm.cstrToJs(s2); s3 = s3 && wasm.cstrToJs(s3);
|
p = wasm.allocFromTypedArray(text);
|
||||||
return xProxy(pV, iCode, s0, s1, s2, s3) || 0;
|
n = text.byteLength;
|
||||||
|
}else if('string'===typeof text){
|
||||||
|
[p, n] = wasm.allocCString(text);
|
||||||
|
}else{
|
||||||
|
return util.sqlite3_wasm_db_error(
|
||||||
|
capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
|
||||||
|
"Invalid 3rd argument type for sqlite3_bind_text()."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
|
||||||
}catch(e){
|
}catch(e){
|
||||||
return util.sqlite3_wasm_db_error(pDb, e);
|
wasm.dealloc(p);
|
||||||
|
return util.sqlite3_wasm_db_error(
|
||||||
|
capi.sqlite3_db_handle(pStmt), e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
}/*sqlite3_bind_text()*/;
|
||||||
|
|
||||||
|
/** Documented in the capi object's initializer. */
|
||||||
|
capi.sqlite3_bind_blob = function f(pStmt, iCol, pMem, nMem, xDestroy){
|
||||||
|
if(f.length!==arguments.length){
|
||||||
|
return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt),
|
||||||
|
"sqlite3_bind_blob", f.length);
|
||||||
|
}else if(wasm.isPtr(pMem) || null===pMem){
|
||||||
|
return __bindBlob(pStmt, iCol, pMem, nMem, xDestroy);
|
||||||
|
}else if(pMem instanceof ArrayBuffer){
|
||||||
|
pMem = new Uint8Array(pMem);
|
||||||
|
}else if(Array.isArray(pMem)){
|
||||||
|
pMem = pMem.join('');
|
||||||
}
|
}
|
||||||
return __ssa(pDb, xAuth, pUserData);
|
let p, n;
|
||||||
};
|
try{
|
||||||
}/* sqlite3_set_authorizer() */
|
if(util.isBindableTypedArray(pMem)){
|
||||||
|
p = wasm.allocFromTypedArray(pMem);
|
||||||
|
n = nMem>=0 ? nMem : pMem.byteLength;
|
||||||
|
}else if('string'===typeof pMem){
|
||||||
|
[p, n] = wasm.allocCString(pMem);
|
||||||
|
}else{
|
||||||
|
return util.sqlite3_wasm_db_error(
|
||||||
|
capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
|
||||||
|
"Invalid 3rd argument type for sqlite3_bind_blob()."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
|
||||||
|
}catch(e){
|
||||||
|
wasm.dealloc(p);
|
||||||
|
return util.sqlite3_wasm_db_error(
|
||||||
|
capi.sqlite3_db_handle(pStmt), e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}/*sqlite3_bind_blob()*/;
|
||||||
|
|
||||||
|
}/*sqlite3_bind_text/blob()*/
|
||||||
|
|
||||||
{/* sqlite3_config() */
|
{/* sqlite3_config() */
|
||||||
/**
|
/**
|
||||||
@ -1130,8 +1202,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
toss("Maintenance required: increase sqlite3_wasm_enum_json()'s",
|
toss("Maintenance required: increase sqlite3_wasm_enum_json()'s",
|
||||||
"static buffer size!");
|
"static buffer size!");
|
||||||
}
|
}
|
||||||
wasm.ctype = JSON.parse(wasm.cstrToJs(cJson));
|
|
||||||
//console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
|
//console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
|
||||||
|
wasm.ctype = JSON.parse(wasm.cstrToJs(cJson));
|
||||||
|
// Groups of SQLITE_xyz macros...
|
||||||
const defineGroups = ['access', 'authorizer',
|
const defineGroups = ['access', 'authorizer',
|
||||||
'blobFinalizers', 'changeset',
|
'blobFinalizers', 'changeset',
|
||||||
'config', 'dataTypes',
|
'config', 'dataTypes',
|
||||||
@ -1139,13 +1212,12 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
'encodings', 'fcntl', 'flock', 'ioCap',
|
'encodings', 'fcntl', 'flock', 'ioCap',
|
||||||
'limits', 'openFlags',
|
'limits', 'openFlags',
|
||||||
'prepareFlags', 'resultCodes',
|
'prepareFlags', 'resultCodes',
|
||||||
'serialize', 'session',
|
|
||||||
'sqlite3Status',
|
'sqlite3Status',
|
||||||
'stmtStatus', 'syncFlags',
|
'stmtStatus', 'syncFlags',
|
||||||
'trace', 'txnState', 'udfFlags',
|
'trace', 'txnState', 'udfFlags',
|
||||||
'version' ];
|
'version' ];
|
||||||
if(wasm.bigIntEnabled){
|
if(wasm.bigIntEnabled){
|
||||||
defineGroups.push('vtab');
|
defineGroups.push('serialize', 'session', 'vtab');
|
||||||
}
|
}
|
||||||
for(const t of defineGroups){
|
for(const t of defineGroups){
|
||||||
for(const e of Object.entries(wasm.ctype[t])){
|
for(const e of Object.entries(wasm.ctype[t])){
|
||||||
@ -1297,4 +1369,5 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
}
|
}
|
||||||
}/*pKvvfs*/
|
}/*pKvvfs*/
|
||||||
|
|
||||||
|
wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
|
||||||
});
|
});
|
||||||
|
@ -337,7 +337,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
*/
|
*/
|
||||||
const Stmt = function(){
|
const Stmt = function(){
|
||||||
if(BindTypes!==arguments[2]){
|
if(BindTypes!==arguments[2]){
|
||||||
toss3("Do not call the Stmt constructor directly. Use DB.prepare().");
|
toss3(capi.SQLITE_MISUSE, "Do not call the Stmt constructor directly. Use DB.prepare().");
|
||||||
}
|
}
|
||||||
this.db = arguments[0];
|
this.db = arguments[0];
|
||||||
__ptrMap.set(this, arguments[1]);
|
__ptrMap.set(this, arguments[1]);
|
||||||
@ -439,22 +439,23 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
if(util.isInt32(opt.rowMode)){
|
if(util.isInt32(opt.rowMode)){
|
||||||
out.cbArg = (stmt)=>stmt.get(opt.rowMode);
|
out.cbArg = (stmt)=>stmt.get(opt.rowMode);
|
||||||
break;
|
break;
|
||||||
}else if('string'===typeof opt.rowMode && opt.rowMode.length>1){
|
}else if('string'===typeof opt.rowMode
|
||||||
|
&& opt.rowMode.length>1
|
||||||
|
&& '$'===opt.rowMode[0]){
|
||||||
/* "$X": fetch column named "X" (case-sensitive!). Prior
|
/* "$X": fetch column named "X" (case-sensitive!). Prior
|
||||||
to 2022-12-14 ":X" and "@X" were also permitted, but
|
to 2022-12-14 ":X" and "@X" were also permitted, but
|
||||||
having so many options is unnecessary and likely to
|
having so many options is unnecessary and likely to
|
||||||
cause confusion. */
|
cause confusion. */
|
||||||
if('$'===opt.rowMode[0]){
|
const $colName = opt.rowMode.substr(1);
|
||||||
out.cbArg = function(stmt){
|
out.cbArg = (stmt)=>{
|
||||||
const rc = stmt.get(this.obj)[this.colName];
|
const rc = stmt.get(Object.create(null))[$colName];
|
||||||
return (undefined===rc) ? toss3("exec(): unknown result column:",this.colName) : rc;
|
return (undefined===rc)
|
||||||
}.bind({
|
? toss3(capi.SQLITE_NOTFOUND,
|
||||||
obj:Object.create(null),
|
"exec(): unknown result column:",$colName)
|
||||||
colName: opt.rowMode.substr(1)
|
: rc;
|
||||||
});
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
toss3("Invalid rowMode:",opt.rowMode);
|
toss3("Invalid rowMode:",opt.rowMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -697,21 +698,27 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
unchanged. Achtung: an SQL result may have multiple columns
|
unchanged. Achtung: an SQL result may have multiple columns
|
||||||
with identical names.
|
with identical names.
|
||||||
|
|
||||||
- `callback` = a function which gets called for each row of
|
- `callback` = a function which gets called for each row of the
|
||||||
the result set, but only if that statement has any result
|
result set, but only if that statement has any result
|
||||||
_rows_. The callback's "this" is the options object, noting
|
_rows_. The callback's "this" is the options object, noting
|
||||||
that this function synthesizes one if the caller does not pass
|
that this function synthesizes one if the caller does not pass
|
||||||
one to exec(). The second argument passed to the callback is
|
one to exec(). The second argument passed to the callback is
|
||||||
always the current Stmt object, as it's needed if the caller
|
always the current Stmt object, as it's needed if the caller
|
||||||
wants to fetch the column names or some such (noting that they
|
wants to fetch the column names or some such (noting that they
|
||||||
could also be fetched via `this.columnNames`, if the client
|
could also be fetched via `this.columnNames`, if the client
|
||||||
provides the `columnNames` option).
|
provides the `columnNames` option). If the callback returns a
|
||||||
|
literal `false` (as opposed to any other falsy value, e.g. an
|
||||||
|
implicit `undefined` return), any ongoing statement-`step()`
|
||||||
|
iteration stops without an error. The return value of the
|
||||||
|
callback is otherwise ignored.
|
||||||
|
|
||||||
ACHTUNG: The callback MUST NOT modify the Stmt object. Calling
|
ACHTUNG: The callback MUST NOT modify the Stmt object. Calling
|
||||||
any of the Stmt.get() variants, Stmt.getColumnName(), or
|
any of the Stmt.get() variants, Stmt.getColumnName(), or
|
||||||
similar, is legal, but calling step() or finalize() is
|
similar, is legal, but calling step() or finalize() is
|
||||||
not. Member methods which are illegal in this context will
|
not. Member methods which are illegal in this context will
|
||||||
trigger an exception.
|
trigger an exception, but clients must also refrain from using
|
||||||
|
any lower-level (C-style) APIs which might modify the
|
||||||
|
statement.
|
||||||
|
|
||||||
The first argument passed to the callback defaults to an array of
|
The first argument passed to the callback defaults to an array of
|
||||||
values from the current result row but may be changed with ...
|
values from the current result row but may be changed with ...
|
||||||
@ -799,7 +806,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
Array.isArray(opt.resultRows) ? opt.resultRows : undefined;
|
Array.isArray(opt.resultRows) ? opt.resultRows : undefined;
|
||||||
let stmt;
|
let stmt;
|
||||||
let bind = opt.bind;
|
let bind = opt.bind;
|
||||||
let evalFirstResult = !!(arg.cbArg || opt.columnNames) /* true to evaluate the first result-returning query */;
|
let evalFirstResult = !!(
|
||||||
|
arg.cbArg || opt.columnNames || resultRows
|
||||||
|
) /* true to step through the first result-returning statement */;
|
||||||
const stack = wasm.scopedAllocPush();
|
const stack = wasm.scopedAllocPush();
|
||||||
const saveSql = Array.isArray(opt.saveSql) ? opt.saveSql : undefined;
|
const saveSql = Array.isArray(opt.saveSql) ? opt.saveSql : undefined;
|
||||||
try{
|
try{
|
||||||
@ -810,9 +819,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
space for the SQL (pSql). When prepare_v2() returns, pzTail
|
space for the SQL (pSql). When prepare_v2() returns, pzTail
|
||||||
will point to somewhere in pSql. */
|
will point to somewhere in pSql. */
|
||||||
let sqlByteLen = isTA ? arg.sql.byteLength : wasm.jstrlen(arg.sql);
|
let sqlByteLen = isTA ? arg.sql.byteLength : wasm.jstrlen(arg.sql);
|
||||||
const ppStmt = wasm.scopedAlloc(/* output (sqlite3_stmt**) arg and pzTail */
|
const ppStmt = wasm.scopedAlloc(
|
||||||
(2 * wasm.ptrSizeof)
|
/* output (sqlite3_stmt**) arg and pzTail */
|
||||||
+ (sqlByteLen + 1/* SQL + NUL */));
|
(2 * wasm.ptrSizeof) + (sqlByteLen + 1/* SQL + NUL */)
|
||||||
|
);
|
||||||
const pzTail = ppStmt + wasm.ptrSizeof /* final arg to sqlite3_prepare_v2() */;
|
const pzTail = ppStmt + wasm.ptrSizeof /* final arg to sqlite3_prepare_v2() */;
|
||||||
let pSql = pzTail + wasm.ptrSizeof;
|
let pSql = pzTail + wasm.ptrSizeof;
|
||||||
const pSqlEnd = pSql + sqlByteLen;
|
const pSqlEnd = pSql + sqlByteLen;
|
||||||
@ -848,11 +858,15 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
if(Array.isArray(opt.columnNames)){
|
if(Array.isArray(opt.columnNames)){
|
||||||
stmt.getColumnNames(opt.columnNames);
|
stmt.getColumnNames(opt.columnNames);
|
||||||
}
|
}
|
||||||
while(!!arg.cbArg && stmt.step()){
|
if(arg.cbArg || resultRows){
|
||||||
|
for(; stmt.step(); stmt._isLocked = false){
|
||||||
stmt._isLocked = true;
|
stmt._isLocked = true;
|
||||||
const row = arg.cbArg(stmt);
|
const row = arg.cbArg(stmt);
|
||||||
if(resultRows) resultRows.push(row);
|
if(resultRows) resultRows.push(row);
|
||||||
if(callback) callback.call(opt, row, stmt);
|
if(callback && false === callback.call(opt, row, stmt)){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
stmt._isLocked = false;
|
stmt._isLocked = false;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@ -873,10 +887,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
}
|
}
|
||||||
return arg.returnVal();
|
return arg.returnVal();
|
||||||
}/*exec()*/,
|
}/*exec()*/,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a new scalar UDF (User-Defined Function) which is
|
Creates a new UDF (User-Defined Function) which is accessible
|
||||||
accessible via SQL code. This function may be called in any
|
via SQL code. This function may be called in any of the
|
||||||
of the following forms:
|
following forms:
|
||||||
|
|
||||||
- (name, function)
|
- (name, function)
|
||||||
- (name, function, optionsObject)
|
- (name, function, optionsObject)
|
||||||
@ -892,10 +907,12 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
functions. Creating an aggregate or window function requires
|
functions. Creating an aggregate or window function requires
|
||||||
the options-object form (see below for details).
|
the options-object form (see below for details).
|
||||||
|
|
||||||
UDFs cannot currently be removed from a DB handle after they're
|
UDFs can be removed as documented for
|
||||||
added. More correctly, they can be removed as documented for
|
sqlite3_create_function_v2() and
|
||||||
sqlite3_create_function_v2(), but doing so will "leak" the
|
sqlite3_create_window_function(), but doing so will "leak" the
|
||||||
JS-created WASM binding of those functions.
|
JS-created WASM binding of those functions (meaning that their
|
||||||
|
entries in the WASM indirect function table still
|
||||||
|
exist). Eliminating that potential leak is a pending TODO.
|
||||||
|
|
||||||
On success, returns this object. Throws on error.
|
On success, returns this object. Throws on error.
|
||||||
|
|
||||||
@ -1213,7 +1230,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
/* else fall through */
|
/* else fall through */
|
||||||
default:
|
default:
|
||||||
//console.log("isSupportedBindType",t,v);
|
//console.log("isSupportedBindType",t,v);
|
||||||
return util.isBindableTypedArray(v) ? BindTypes.blob : undefined;
|
return (util.isBindableTypedArray(v) || (v instanceof ArrayBuffer))
|
||||||
|
? BindTypes.blob : undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1267,7 +1285,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
success.
|
success.
|
||||||
*/
|
*/
|
||||||
const bindOne = function f(stmt,ndx,bindType,val){
|
const bindOne = function f(stmt,ndx,bindType,val){
|
||||||
affirmUnlocked(stmt, 'bind()');
|
affirmUnlocked(affirmStmtOpen(stmt), 'bind()');
|
||||||
if(!f._){
|
if(!f._){
|
||||||
f._tooBigInt = (v)=>toss3(
|
f._tooBigInt = (v)=>toss3(
|
||||||
"BigInt value is too big to store without precision loss:", v
|
"BigInt value is too big to store without precision loss:", v
|
||||||
@ -1277,14 +1295,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
so we have no range checking. */
|
so we have no range checking. */
|
||||||
f._ = {
|
f._ = {
|
||||||
string: function(stmt, ndx, val, asBlob){
|
string: function(stmt, ndx, val, asBlob){
|
||||||
const stack = wasm.scopedAllocPush();
|
const [pStr, n] = wasm.allocCString(val, true);
|
||||||
try{
|
|
||||||
const [pStr, n] = wasm.scopedAllocCString(val, true);
|
|
||||||
const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
|
const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
|
||||||
return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_TRANSIENT);
|
return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_WASM_DEALLOC);
|
||||||
}finally{
|
|
||||||
wasm.scopedAllocPop(stack);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}/* static init */
|
}/* static init */
|
||||||
@ -1329,29 +1342,17 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
case BindTypes.blob: {
|
case BindTypes.blob: {
|
||||||
if('string'===typeof val){
|
if('string'===typeof val){
|
||||||
rc = f._.string(stmt, ndx, val, true);
|
rc = f._.string(stmt, ndx, val, true);
|
||||||
|
break;
|
||||||
|
}else if(val instanceof ArrayBuffer){
|
||||||
|
val = new Uint8Array(val);
|
||||||
}else if(!util.isBindableTypedArray(val)){
|
}else if(!util.isBindableTypedArray(val)){
|
||||||
toss3("Binding a value as a blob requires",
|
toss3("Binding a value as a blob requires",
|
||||||
"that it be a string, Uint8Array, or Int8Array.");
|
"that it be a string, Uint8Array, Int8Array, or ArrayBuffer.");
|
||||||
}else if(1){
|
}
|
||||||
/* _Hypothetically_ more efficient than the impl in the 'else' block. */
|
const pBlob = wasm.alloc(val.byteLength || 1);
|
||||||
const stack = wasm.scopedAllocPush();
|
|
||||||
try{
|
|
||||||
const pBlob = wasm.scopedAlloc(val.byteLength || 1);
|
|
||||||
wasm.heap8().set(val.byteLength ? val : [0], pBlob)
|
wasm.heap8().set(val.byteLength ? val : [0], pBlob)
|
||||||
rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
|
rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
|
||||||
capi.SQLITE_TRANSIENT);
|
capi.SQLITE_WASM_DEALLOC);
|
||||||
}finally{
|
|
||||||
wasm.scopedAllocPop(stack);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
const pBlob = wasm.allocFromTypedArray(val);
|
|
||||||
try{
|
|
||||||
rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
|
|
||||||
capi.SQLITE_TRANSIENT);
|
|
||||||
}finally{
|
|
||||||
wasm.dealloc(pBlob);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -1359,6 +1360,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
toss3("Unsupported bind() argument type: "+(typeof val));
|
toss3("Unsupported bind() argument type: "+(typeof val));
|
||||||
}
|
}
|
||||||
if(rc) DB.checkRc(stmt.db.pointer, rc);
|
if(rc) DB.checkRc(stmt.db.pointer, rc);
|
||||||
|
stmt._mayGet = false;
|
||||||
return stmt;
|
return stmt;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1446,8 +1448,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
- Strings are bound as strings (use bindAsBlob() to force
|
- Strings are bound as strings (use bindAsBlob() to force
|
||||||
blob binding).
|
blob binding).
|
||||||
|
|
||||||
- Uint8Array and Int8Array instances are bound as blobs.
|
- Uint8Array, Int8Array, and ArrayBuffer instances are bound as
|
||||||
(TODO: binding the other TypedArray types.)
|
blobs. (TODO? binding the other TypedArray types.)
|
||||||
|
|
||||||
If passed an array, each element of the array is bound at
|
If passed an array, each element of the array is bound at
|
||||||
the parameter index equal to the array index plus 1
|
the parameter index equal to the array index plus 1
|
||||||
@ -1502,8 +1504,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
}
|
}
|
||||||
arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v));
|
arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v));
|
||||||
return this;
|
return this;
|
||||||
|
}else if(arg instanceof ArrayBuffer){
|
||||||
|
arg = new Uint8Array(arg);
|
||||||
}
|
}
|
||||||
else if('object'===typeof arg/*null was checked above*/
|
if('object'===typeof arg/*null was checked above*/
|
||||||
&& !util.isBindableTypedArray(arg)){
|
&& !util.isBindableTypedArray(arg)){
|
||||||
/* Treat each property of arg as a named bound parameter. */
|
/* Treat each property of arg as a named bound parameter. */
|
||||||
if(1!==arguments.length){
|
if(1!==arguments.length){
|
||||||
@ -1525,7 +1529,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
the value. The ndx may be a numbered or named bind index. The
|
the value. The ndx may be a numbered or named bind index. The
|
||||||
value must be of type string, null/undefined (both get treated
|
value must be of type string, null/undefined (both get treated
|
||||||
as null), or a TypedArray of a type supported by the bind()
|
as null), or a TypedArray of a type supported by the bind()
|
||||||
API.
|
API. This API cannot bind numbers as blobs.
|
||||||
|
|
||||||
If passed a single argument, a bind index of 1 is assumed and
|
If passed a single argument, a bind index of 1 is assumed and
|
||||||
the first argument is the value.
|
the first argument is the value.
|
||||||
@ -1541,9 +1545,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
&& BindTypes.null !== t){
|
&& BindTypes.null !== t){
|
||||||
toss3("Invalid value type for bindAsBlob()");
|
toss3("Invalid value type for bindAsBlob()");
|
||||||
}
|
}
|
||||||
bindOne(this, ndx, BindTypes.blob, arg);
|
return bindOne(this, ndx, BindTypes.blob, arg);
|
||||||
this._mayGet = false;
|
|
||||||
return this;
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
Steps the statement one time. If the result indicates that a
|
Steps the statement one time. If the result indicates that a
|
||||||
|
@ -321,14 +321,17 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if v appears to be one of our bind()-able TypedArray
|
Returns v if v appears to be one of our bind()-able TypedArray
|
||||||
types: Uint8Array or Int8Array. Support for TypedArrays with
|
types: Uint8Array or Int8Array or ArrayBuffer. Support for
|
||||||
element sizes >1 is a potential TODO just waiting on a use case
|
TypedArrays with element sizes >1 is a potential TODO just
|
||||||
to justify them.
|
waiting on a use case to justify them. Until then, their `buffer`
|
||||||
|
property can be used to pass them as an ArrayBuffer. If it's not
|
||||||
|
a bindable array type, a falsy value is returned.
|
||||||
*/
|
*/
|
||||||
const isBindableTypedArray = (v)=>{
|
const isBindableTypedArray = (v)=>{
|
||||||
return v && (v instanceof Uint8Array || v instanceof Int8Array);
|
return v && (v instanceof Uint8Array
|
||||||
//v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT);
|
|| v instanceof Int8Array
|
||||||
|
|| v instanceof ArrayBuffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -341,8 +344,9 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
isSQLableTypedArray() list.
|
isSQLableTypedArray() list.
|
||||||
*/
|
*/
|
||||||
const isSQLableTypedArray = (v)=>{
|
const isSQLableTypedArray = (v)=>{
|
||||||
return v && (v instanceof Uint8Array || v instanceof Int8Array);
|
return v && (v instanceof Uint8Array
|
||||||
//v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT);
|
|| v instanceof Int8Array
|
||||||
|
|| v instanceof ArrayBuffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Returns true if isBindableTypedArray(v) does, else throws with a message
|
/** Returns true if isBindableTypedArray(v) does, else throws with a message
|
||||||
@ -401,6 +405,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
}else{
|
}else{
|
||||||
super("Allocation failed.");
|
super("Allocation failed.");
|
||||||
}
|
}
|
||||||
|
this.resultCode = capi.SQLITE_NOMEM;
|
||||||
this.name = 'WasmAllocError';
|
this.name = 'WasmAllocError';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -417,6 +422,92 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
};
|
};
|
||||||
|
|
||||||
Object.assign(capi, {
|
Object.assign(capi, {
|
||||||
|
/**
|
||||||
|
sqlite3_bind_blob() works exactly like its C counterpart unless
|
||||||
|
its 3rd argument is one of:
|
||||||
|
|
||||||
|
- JS string: the 3rd argument is converted to a C string, the
|
||||||
|
4th argument is ignored, and the C-string's length is used
|
||||||
|
in its place.
|
||||||
|
|
||||||
|
- Array: converted to a string as defined for "flexible
|
||||||
|
strings" and then it's treated as a JS string.
|
||||||
|
|
||||||
|
- Int8Array or Uint8Array: wasm.allocFromTypedArray() is used to
|
||||||
|
conver the memory to the WASM heap. If the 4th argument is
|
||||||
|
0 or greater, it is used as-is, otherwise the array's byteLength
|
||||||
|
value is used. This is an exception to the C API's undefined
|
||||||
|
behavior for a negative 4th argument, but results are undefined
|
||||||
|
if the given 4th argument value is greater than the byteLength
|
||||||
|
of the input array.
|
||||||
|
|
||||||
|
- If it's an ArrayBuffer, it gets wrapped in a Uint8Array and
|
||||||
|
treated as that type.
|
||||||
|
|
||||||
|
In all of those cases, the final argument (destructor) is
|
||||||
|
ignored and capi.SQLITE_WASM_DEALLOC is assumed.
|
||||||
|
|
||||||
|
A 3rd argument of `null` is treated as if it were a WASM pointer
|
||||||
|
of 0.
|
||||||
|
|
||||||
|
If the 3rd argument is neither a WASM pointer nor one of the
|
||||||
|
above-described types, capi.SQLITE_MISUSE is returned.
|
||||||
|
|
||||||
|
The first argument may be either an `sqlite3_stmt*` WASM
|
||||||
|
pointer or an sqlite3.oo1.Stmt instance.
|
||||||
|
|
||||||
|
For consistency with the C API, it requires the same number of
|
||||||
|
arguments. It returns capi.SQLITE_MISUSE if passed any other
|
||||||
|
argument count.
|
||||||
|
*/
|
||||||
|
sqlite3_bind_blob: undefined/*installed later*/,
|
||||||
|
|
||||||
|
/**
|
||||||
|
sqlite3_bind_text() works exactly like its C counterpart unless
|
||||||
|
its 3rd argument is one of:
|
||||||
|
|
||||||
|
- JS string: the 3rd argument is converted to a C string, the
|
||||||
|
4th argument is ignored, and the C-string's length is used
|
||||||
|
in its place.
|
||||||
|
|
||||||
|
- Array: converted to a string as defined for "flexible
|
||||||
|
strings". The 4th argument is ignored and a value of -1
|
||||||
|
is assumed.
|
||||||
|
|
||||||
|
- Int8Array or Uint8Array: is assumed to contain UTF-8 text, is
|
||||||
|
converted to a string. The 4th argument is ignored, replaced
|
||||||
|
by the array's byteLength value.
|
||||||
|
|
||||||
|
- If it's an ArrayBuffer, it gets wrapped in a Uint8Array and
|
||||||
|
treated as that type.
|
||||||
|
|
||||||
|
In each of those cases, the final argument (text destructor) is
|
||||||
|
ignored and capi.SQLITE_WASM_DEALLOC is assumed.
|
||||||
|
|
||||||
|
A 3rd argument of `null` is treated as if it were a WASM pointer
|
||||||
|
of 0.
|
||||||
|
|
||||||
|
If the 3rd argument is neither a WASM pointer nor one of the
|
||||||
|
above-described types, capi.SQLITE_MISUSE is returned.
|
||||||
|
|
||||||
|
The first argument may be either an `sqlite3_stmt*` WASM
|
||||||
|
pointer or an sqlite3.oo1.Stmt instance.
|
||||||
|
|
||||||
|
For consistency with the C API, it requires the same number of
|
||||||
|
arguments. It returns capi.SQLITE_MISUSE if passed any other
|
||||||
|
argument count.
|
||||||
|
|
||||||
|
If client code needs to bind partial strings, it needs to
|
||||||
|
either parcel the string up before passing it in here or it
|
||||||
|
must pass in a WASM pointer for the 3rd argument and a valid
|
||||||
|
4th-argument value, taking care not to pass a value which
|
||||||
|
truncates a multi-byte UTF-8 character. When passing
|
||||||
|
WASM-format strings, it is important that the final argument be
|
||||||
|
valid or unexpected content can result can result, or even a
|
||||||
|
crash if the application reads past the WASM heap bounds.
|
||||||
|
*/
|
||||||
|
sqlite3_bind_text: undefined/*installed later*/,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
sqlite3_create_function_v2() differs from its native
|
sqlite3_create_function_v2() differs from its native
|
||||||
counterpart only in the following ways:
|
counterpart only in the following ways:
|
||||||
@ -525,18 +616,18 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
WASM build is compiled with emcc's `-sALLOW_TABLE_GROWTH`
|
WASM build is compiled with emcc's `-sALLOW_TABLE_GROWTH`
|
||||||
flag.
|
flag.
|
||||||
*/
|
*/
|
||||||
sqlite3_create_function_v2: function(
|
sqlite3_create_function_v2: (
|
||||||
pDb, funcName, nArg, eTextRep, pApp,
|
pDb, funcName, nArg, eTextRep, pApp,
|
||||||
xFunc, xStep, xFinal, xDestroy
|
xFunc, xStep, xFinal, xDestroy
|
||||||
){/*installed later*/},
|
)=>{/*installed later*/},
|
||||||
/**
|
/**
|
||||||
Equivalent to passing the same arguments to
|
Equivalent to passing the same arguments to
|
||||||
sqlite3_create_function_v2(), with 0 as the final argument.
|
sqlite3_create_function_v2(), with 0 as the final argument.
|
||||||
*/
|
*/
|
||||||
sqlite3_create_function:function(
|
sqlite3_create_function: (
|
||||||
pDb, funcName, nArg, eTextRep, pApp,
|
pDb, funcName, nArg, eTextRep, pApp,
|
||||||
xFunc, xStep, xFinal
|
xFunc, xStep, xFinal
|
||||||
){/*installed later*/},
|
)=>{/*installed later*/},
|
||||||
/**
|
/**
|
||||||
The sqlite3_create_window_function() JS wrapper differs from
|
The sqlite3_create_window_function() JS wrapper differs from
|
||||||
its native implementation in the exact same way that
|
its native implementation in the exact same way that
|
||||||
@ -544,10 +635,10 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
xInverse(), is treated identically to xStep() by the wrapping
|
xInverse(), is treated identically to xStep() by the wrapping
|
||||||
layer.
|
layer.
|
||||||
*/
|
*/
|
||||||
sqlite3_create_window_function: function(
|
sqlite3_create_window_function: (
|
||||||
pDb, funcName, nArg, eTextRep, pApp,
|
pDb, funcName, nArg, eTextRep, pApp,
|
||||||
xStep, xFinal, xValue, xInverse, xDestroy
|
xStep, xFinal, xValue, xInverse, xDestroy
|
||||||
){/*installed later*/},
|
)=>{/*installed later*/},
|
||||||
/**
|
/**
|
||||||
The sqlite3_prepare_v3() binding handles two different uses
|
The sqlite3_prepare_v3() binding handles two different uses
|
||||||
with differing JS/WASM semantics:
|
with differing JS/WASM semantics:
|
||||||
@ -1575,7 +1666,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
- `bigint`: similar to `number` but will trigger an error if the
|
- `bigint`: similar to `number` but will trigger an error if the
|
||||||
value is too big to store in an int64.
|
value is too big to store in an int64.
|
||||||
- `string`: `sqlite3_result_text()`
|
- `string`: `sqlite3_result_text()`
|
||||||
- Uint8Array or Int8Array: `sqlite3_result_blob()`
|
- Uint8Array or Int8Array or ArrayBuffer: `sqlite3_result_blob()`
|
||||||
- `undefined`: is a no-op provided to simplify certain use cases.
|
- `undefined`: is a no-op provided to simplify certain use cases.
|
||||||
|
|
||||||
Anything else triggers `sqlite3_result_error()` with a
|
Anything else triggers `sqlite3_result_error()` with a
|
||||||
@ -1626,9 +1717,11 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
f(pCtx, val);
|
f(pCtx, val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'string':
|
case 'string': {
|
||||||
capi.sqlite3_result_text(pCtx, val, -1, capi.SQLITE_TRANSIENT);
|
const [p, n] = wasm.allocCString(val,true);
|
||||||
|
capi.sqlite3_result_text(pCtx, p, n, capi.SQLITE_WASM_DEALLOC);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'object':
|
case 'object':
|
||||||
if(null===val/*yes, typeof null === 'object'*/) {
|
if(null===val/*yes, typeof null === 'object'*/) {
|
||||||
capi.sqlite3_result_null(pCtx);
|
capi.sqlite3_result_null(pCtx);
|
||||||
@ -1637,7 +1730,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
const pBlob = wasm.allocFromTypedArray(val);
|
const pBlob = wasm.allocFromTypedArray(val);
|
||||||
capi.sqlite3_result_blob(
|
capi.sqlite3_result_blob(
|
||||||
pCtx, pBlob, val.byteLength,
|
pCtx, pBlob, val.byteLength,
|
||||||
wasm.exports[sqlite3.config.deallocExportName]
|
capi.SQLITE_WASM_DEALLOC
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1657,8 +1750,8 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
argument of sqlite3_value_to_js(). If the sqlite3_column_value()
|
argument of sqlite3_value_to_js(). If the sqlite3_column_value()
|
||||||
returns NULL (e.g. because the column index is out of range),
|
returns NULL (e.g. because the column index is out of range),
|
||||||
this function returns `undefined`, regardless of the 3rd
|
this function returns `undefined`, regardless of the 3rd
|
||||||
argument. 3rd argument is falsy and conversion fails, `undefined`
|
argument. If the 3rd argument is falsy and conversion fails,
|
||||||
will be returned.
|
`undefined` will be returned.
|
||||||
|
|
||||||
Note that sqlite3_column_value() returns an "unprotected" value
|
Note that sqlite3_column_value() returns an "unprotected" value
|
||||||
object, but in a single-threaded environment (like this one)
|
object, but in a single-threaded environment (like this one)
|
||||||
|
@ -329,12 +329,14 @@ SQLITE_WASM_KEEP int sqlite3_wasm_pstack_quota(void){
|
|||||||
*/
|
*/
|
||||||
SQLITE_WASM_KEEP
|
SQLITE_WASM_KEEP
|
||||||
int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
|
int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
|
||||||
|
if( db!=0 ){
|
||||||
if( 0!=zMsg ){
|
if( 0!=zMsg ){
|
||||||
const int nMsg = sqlite3Strlen30(zMsg);
|
const int nMsg = sqlite3Strlen30(zMsg);
|
||||||
sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg);
|
sqlite3ErrorWithMsg(db, err_code, "%.*s", nMsg, zMsg);
|
||||||
}else{
|
}else{
|
||||||
sqlite3ErrorWithMsg(db, err_code, NULL);
|
sqlite3ErrorWithMsg(db, err_code, NULL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return err_code;
|
return err_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1648,6 +1650,11 @@ int sqlite3_wasm_test_intptr(int * p){
|
|||||||
return *p = *p * 2;
|
return *p = *p * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SQLITE_WASM_KEEP
|
||||||
|
void * sqlite3_wasm_test_voidptr(void * p){
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
SQLITE_WASM_KEEP
|
SQLITE_WASM_KEEP
|
||||||
int64_t sqlite3_wasm_test_int64_max(void){
|
int64_t sqlite3_wasm_test_int64_max(void){
|
||||||
return (int64_t)0x7fffffffffffffff;
|
return (int64_t)0x7fffffffffffffff;
|
||||||
|
@ -1406,7 +1406,8 @@ self.WhWasmUtilInstaller = function(target){
|
|||||||
.set('int', xArg.get('i32'))
|
.set('int', xArg.get('i32'))
|
||||||
.set('null', (i)=>i)
|
.set('null', (i)=>i)
|
||||||
.set(null, xArg.get('null'))
|
.set(null, xArg.get('null'))
|
||||||
.set('**', __xArgPtr);
|
.set('**', __xArgPtr)
|
||||||
|
.set('*', __xArgPtr);
|
||||||
xResult.set('*', __xArgPtr)
|
xResult.set('*', __xArgPtr)
|
||||||
.set('pointer', __xArgPtr)
|
.set('pointer', __xArgPtr)
|
||||||
.set('number', (v)=>Number(v))
|
.set('number', (v)=>Number(v))
|
||||||
@ -1448,20 +1449,20 @@ self.WhWasmUtilInstaller = function(target){
|
|||||||
if('string'===typeof v) return target.scopedAllocCString(v);
|
if('string'===typeof v) return target.scopedAllocCString(v);
|
||||||
return v ? __xArgPtr(v) : null;
|
return v ? __xArgPtr(v) : null;
|
||||||
};
|
};
|
||||||
xArg.set('string', __xArgString);
|
xArg.set('string', __xArgString)
|
||||||
xArg.set('utf8', __xArgString);
|
.set('utf8', __xArgString)
|
||||||
xArg.set('pointer', __xArgString);
|
.set('pointer', __xArgString);
|
||||||
xArg.set('*', __xArgString);
|
//xArg.set('*', __xArgString);
|
||||||
|
|
||||||
xResult.set('string', (i)=>target.cstrToJs(i));
|
xResult.set('string', (i)=>target.cstrToJs(i))
|
||||||
xResult.set('utf8', xResult.get('string'));
|
.set('utf8', xResult.get('string'))
|
||||||
xResult.set('string:dealloc', (i)=>{
|
.set('string:dealloc', (i)=>{
|
||||||
try { return i ? target.cstrToJs(i) : null }
|
try { return i ? target.cstrToJs(i) : null }
|
||||||
finally{ target.dealloc(i) }
|
finally{ target.dealloc(i) }
|
||||||
});
|
})
|
||||||
xResult.set('utf8:dealloc', xResult.get('string:dealloc'));
|
.set('utf8:dealloc', xResult.get('string:dealloc'))
|
||||||
xResult.set('json', (i)=>JSON.parse(target.cstrToJs(i)));
|
.set('json', (i)=>JSON.parse(target.cstrToJs(i)))
|
||||||
xResult.set('json:dealloc', (i)=>{
|
.set('json:dealloc', (i)=>{
|
||||||
try{ return i ? JSON.parse(target.cstrToJs(i)) : null }
|
try{ return i ? JSON.parse(target.cstrToJs(i)) : null }
|
||||||
finally{ target.dealloc(i) }
|
finally{ target.dealloc(i) }
|
||||||
});
|
});
|
||||||
@ -1495,7 +1496,7 @@ self.WhWasmUtilInstaller = function(target){
|
|||||||
types are indeterminate, whereas the LHS values will be
|
types are indeterminate, whereas the LHS values will be
|
||||||
WASM-compatible values by the time this is called.
|
WASM-compatible values by the time this is called.
|
||||||
*/
|
*/
|
||||||
convertArg(v,argIndex,argv){
|
convertArg(v,argv,argIndex){
|
||||||
toss("AbstractArgAdapter must be subclassed.");
|
toss("AbstractArgAdapter must be subclassed.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1540,24 +1541,38 @@ self.WhWasmUtilInstaller = function(target){
|
|||||||
context. This mode is the default if bindScope is _not_ set
|
context. This mode is the default if bindScope is _not_ set
|
||||||
but a property named contextKey (described below) is.
|
but a property named contextKey (described below) is.
|
||||||
|
|
||||||
|
- callProxy (function): if set, this must be a function which
|
||||||
|
will act as a proxy for any "converted" JS function. It is
|
||||||
|
passed the being-converted function value and must return
|
||||||
|
either that function or a function which acts on its
|
||||||
|
behalf. The returned function will be the one which gets
|
||||||
|
installed into the WASM function table. The proxy must perform
|
||||||
|
any required argument conversion (noting that it will be called
|
||||||
|
from C code, so will receive C-format arguments) before passing
|
||||||
|
them on to the being-converted function. Whether or not the
|
||||||
|
proxy itself must return a value depends on the context. If it
|
||||||
|
does, it must be a WASM-friendly value, as it will be returning
|
||||||
|
from a call made from native code.
|
||||||
|
|
||||||
- contextKey (function): is only used if bindScope is 'context'
|
- contextKey (function): is only used if bindScope is 'context'
|
||||||
or if bindScope is not set and this function is, in which case
|
or if bindScope is not set and this function is, in which case
|
||||||
'context' is assumed. This function gets passed
|
'context' is assumed. This function gets bound to this object,
|
||||||
(argIndex,argv), where argIndex is the index of _this_ function
|
so its "this" is this object. It gets passed (argv,argIndex),
|
||||||
pointer in its _wrapping_ function's arguments and argv is the
|
where argIndex is the index of _this_ function pointer in its
|
||||||
_current_ still-being-xWrap()-processed args array. All
|
_wrapping_ function's arguments and argv is the _current_
|
||||||
arguments to the left of argIndex will have been processed by
|
still-being-xWrap()-processed args array. All arguments to the
|
||||||
xWrap() by the time this is called. argv[argIndex] will be the
|
left of argIndex will have been processed by xWrap() by the
|
||||||
value the user passed in to the xWrap()'d function for the
|
time this is called. argv[argIndex] will be the value the user
|
||||||
argument this FuncPtrAdapter is mapped to. Arguments to the
|
passed in to the xWrap()'d function for the argument this
|
||||||
right of argv[argIndex] will not yet have been converted before
|
FuncPtrAdapter is mapped to. Arguments to the right of
|
||||||
this is called. The function must return a key which uniquely
|
argv[argIndex] will not yet have been converted before this is
|
||||||
|
called. The function must return a key which uniquely
|
||||||
identifies this function mapping context for _this_
|
identifies this function mapping context for _this_
|
||||||
FuncPtrAdapter instance (other instances are not considered),
|
FuncPtrAdapter instance (other instances are not considered),
|
||||||
taking into account that C functions often take some sort of
|
taking into account that C functions often take some sort of
|
||||||
state object as one or more of their arguments. As an example,
|
state object as one or more of their arguments. As an example,
|
||||||
if the xWrap()'d function takes `(int,T*,functionPtr,X*)` and
|
if the xWrap()'d function takes `(int,T*,functionPtr,X*)` and
|
||||||
this FuncPtrAdapter is the argv[2]nd arg, contextKey(2,argv)
|
this FuncPtrAdapter is the argv[2]nd arg, contextKey(argv,2)
|
||||||
might return 'T@'+argv[1], or even just argv[1]. Note,
|
might return 'T@'+argv[1], or even just argv[1]. Note,
|
||||||
however, that the (X*) argument will not yet have been
|
however, that the (X*) argument will not yet have been
|
||||||
processed by the time this is called and should not be used as
|
processed by the time this is called and should not be used as
|
||||||
@ -1569,7 +1584,7 @@ self.WhWasmUtilInstaller = function(target){
|
|||||||
use their pointers in the key because most C-strings in this
|
use their pointers in the key because most C-strings in this
|
||||||
constellation are transient.
|
constellation are transient.
|
||||||
|
|
||||||
Yes, that ^^^ is a bit awkward, but it's what we have.
|
Yes, that ^^^ is quite awkward, but it's what we have.
|
||||||
|
|
||||||
The constructor only saves the above state for later, and does
|
The constructor only saves the above state for later, and does
|
||||||
not actually bind any functions. Its convertArg() method is
|
not actually bind any functions. Its convertArg() method is
|
||||||
@ -1593,6 +1608,11 @@ self.WhWasmUtilInstaller = function(target){
|
|||||||
xArg.FuncPtrAdapter = class FuncPtrAdapter extends AbstractArgAdapter {
|
xArg.FuncPtrAdapter = class FuncPtrAdapter extends AbstractArgAdapter {
|
||||||
constructor(opt) {
|
constructor(opt) {
|
||||||
super(opt);
|
super(opt);
|
||||||
|
if(xArg.FuncPtrAdapter.warnOnUse){
|
||||||
|
console.warn('xArg.FuncPtrAdapter is an internal-only API',
|
||||||
|
'and is not intended to be invoked from',
|
||||||
|
'client-level code. Invoked with:',opt);
|
||||||
|
}
|
||||||
this.signature = opt.signature;
|
this.signature = opt.signature;
|
||||||
if(!opt.bindScope && (opt.contextKey instanceof Function)){
|
if(!opt.bindScope && (opt.contextKey instanceof Function)){
|
||||||
opt.bindScope = 'context';
|
opt.bindScope = 'context';
|
||||||
@ -1607,14 +1627,18 @@ self.WhWasmUtilInstaller = function(target){
|
|||||||
if( ('singleton'===this.bindScope) ) this.singleton = [];
|
if( ('singleton'===this.bindScope) ) this.singleton = [];
|
||||||
else this.singleton = undefined;
|
else this.singleton = undefined;
|
||||||
//console.warn("FuncPtrAdapter()",opt,this);
|
//console.warn("FuncPtrAdapter()",opt,this);
|
||||||
|
this.callProxy = (opt.callProxy instanceof Function)
|
||||||
|
? opt.callProxy : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static warnOnUse = false;
|
||||||
|
|
||||||
static bindScopes = [
|
static bindScopes = [
|
||||||
'transient', 'context', 'singleton'
|
'transient', 'context', 'singleton'
|
||||||
];
|
];
|
||||||
|
|
||||||
/* Dummy impl. Overwritten per-instance as needed. */
|
/* Dummy impl. Overwritten per-instance as needed. */
|
||||||
contextKey(argIndex,argv){
|
contextKey(argv,argIndex){
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1647,14 +1671,16 @@ self.WhWasmUtilInstaller = function(target){
|
|||||||
See the parent class's convertArg() docs for details on what
|
See the parent class's convertArg() docs for details on what
|
||||||
exactly the 2nd and 3rd arguments are.
|
exactly the 2nd and 3rd arguments are.
|
||||||
*/
|
*/
|
||||||
convertArg(v,argIndex,argv){
|
convertArg(v,argv,argIndex){
|
||||||
//console.warn("FuncPtrAdapter.convertArg()",this.signature,this.transient,v);
|
//console.warn("FuncPtrAdapter.convertArg()",this.signature,this.transient,v);
|
||||||
let pair = this.singleton;
|
let pair = this.singleton;
|
||||||
if(!pair && this.isContext){
|
if(!pair && this.isContext){
|
||||||
pair = this.contextMap(this.contextKey(argIndex, argv));
|
pair = this.contextMap(this.contextKey(argv,argIndex));
|
||||||
}
|
}
|
||||||
if(pair && pair[0]===v) return pair[1];
|
if(pair && pair[0]===v) return pair[1];
|
||||||
if(v instanceof Function){
|
if(v instanceof Function){
|
||||||
|
/* Install a WASM binding and return its pointer. */
|
||||||
|
if(this.callProxy) v = this.callProxy(v);
|
||||||
const fp = __installFunction(v, this.signature, this.isTransient);
|
const fp = __installFunction(v, this.signature, this.isTransient);
|
||||||
if(pair){
|
if(pair){
|
||||||
/* Replace existing stashed mapping */
|
/* Replace existing stashed mapping */
|
||||||
@ -1669,10 +1695,10 @@ self.WhWasmUtilInstaller = function(target){
|
|||||||
}else if(target.isPtr(v) || null===v || undefined===v){
|
}else if(target.isPtr(v) || null===v || undefined===v){
|
||||||
if(pair && pair[1] && pair[1]!==v){
|
if(pair && pair[1] && pair[1]!==v){
|
||||||
/* uninstall stashed mapping and replace stashed mapping with v. */
|
/* uninstall stashed mapping and replace stashed mapping with v. */
|
||||||
//console.warn("FuncPtrAdapter is uninstalling function", this.contextKey(argIndex,argv),v);
|
//console.warn("FuncPtrAdapter is uninstalling function", this.contextKey(argv,argIndex),v);
|
||||||
try{target.uninstallFunction(pair[1])}
|
try{target.uninstallFunction(pair[1])}
|
||||||
catch(e){/*ignored*/}
|
catch(e){/*ignored*/}
|
||||||
pair[0] = pair[1] = (v || 0);
|
pair[0] = pair[1] = (v | 0);
|
||||||
}
|
}
|
||||||
return v || 0;
|
return v || 0;
|
||||||
}else{
|
}else{
|
||||||
@ -1758,10 +1784,13 @@ self.WhWasmUtilInstaller = function(target){
|
|||||||
- `N*` (args): a type name in the form `N*`, where N is a numeric
|
- `N*` (args): a type name in the form `N*`, where N is a numeric
|
||||||
type name, is treated the same as WASM pointer.
|
type name, is treated the same as WASM pointer.
|
||||||
|
|
||||||
- `*` and `pointer` (args): have multple semantics. They
|
- `*` and `pointer` (args): are assumed to be WASM pointer values
|
||||||
behave exactly as described below for `string` args.
|
and are returned coerced to an appropriately-sized pointer
|
||||||
|
value (i32 or i64). Non-numeric values will coerce to 0 and
|
||||||
|
out-of-range values will have undefined results (just as with
|
||||||
|
any pointer misuse).
|
||||||
|
|
||||||
- `*` and `pointer` (results): are aliases for the current
|
- `*` and `pointer` (results): aliases for the current
|
||||||
WASM pointer numeric type.
|
WASM pointer numeric type.
|
||||||
|
|
||||||
- `**` (args): is simply a descriptive alias for the WASM pointer
|
- `**` (args): is simply a descriptive alias for the WASM pointer
|
||||||
@ -1903,17 +1932,20 @@ self.WhWasmUtilInstaller = function(target){
|
|||||||
The public interface of argument adapters is that they take
|
The public interface of argument adapters is that they take
|
||||||
ONE argument and return a (possibly) converted result for
|
ONE argument and return a (possibly) converted result for
|
||||||
it. The passing-on of arguments after the first is an
|
it. The passing-on of arguments after the first is an
|
||||||
internal impl. detail for the sake of AbstractArgAdapter, and
|
internal implementation detail for the sake of
|
||||||
not to be relied on or documented for other cases. The fact
|
AbstractArgAdapter, and not to be relied on or documented
|
||||||
that this is how AbstractArgAdapter.convertArgs() gets its 2nd+
|
for other cases. The fact that this is how
|
||||||
arguments, and how FuncPtrAdapter.contextKey() gets its
|
AbstractArgAdapter.convertArgs() gets its 2nd+ arguments,
|
||||||
args, is also an implementation detail and subject to
|
and how FuncPtrAdapter.contextKey() gets its args, is also
|
||||||
change. i.e. the public interface of 1 argument is stable.
|
an implementation detail and subject to change. i.e. the
|
||||||
The fact that any arguments may be passed in after that one,
|
public interface of 1 argument is stable. The fact that any
|
||||||
and what those arguments are, is _not_ part of the public
|
arguments may be passed in after that one, and what those
|
||||||
interface and is _not_ stable.
|
arguments are, is _not_ part of the public interface and is
|
||||||
|
_not_ stable.
|
||||||
*/
|
*/
|
||||||
for(const i in args) args[i] = cxw.convertArgNoCheck(argTypes[i], args[i], i, args);
|
for(const i in args) args[i] = cxw.convertArgNoCheck(
|
||||||
|
argTypes[i], args[i], args, i
|
||||||
|
);
|
||||||
return cxw.convertResultNoCheck(resultType, xf.apply(null,args));
|
return cxw.convertResultNoCheck(resultType, xf.apply(null,args));
|
||||||
}finally{
|
}finally{
|
||||||
target.scopedAllocPop(scope);
|
target.scopedAllocPop(scope);
|
||||||
|
@ -1219,7 +1219,7 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
})
|
})
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
.t('DB.Stmt', function(S){
|
.t('DB.Stmt', function(sqlite3){
|
||||||
let st = this.db.prepare(
|
let st = this.db.prepare(
|
||||||
new TextEncoder('utf-8').encode("select 3 as a")
|
new TextEncoder('utf-8').encode("select 3 as a")
|
||||||
);
|
);
|
||||||
@ -1274,6 +1274,12 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
}
|
}
|
||||||
T.assert(!st.pointer)
|
T.assert(!st.pointer)
|
||||||
.assert(0===this.db.openStatementCount());
|
.assert(0===this.db.openStatementCount());
|
||||||
|
|
||||||
|
T.mustThrowMatching(()=>new sqlite3.oo1.Stmt("hi"), function(err){
|
||||||
|
return (err instanceof sqlite3.SQLite3Error)
|
||||||
|
&& capi.SQLITE_MISUSE === err.resultCode
|
||||||
|
&& 0 < err.message.indexOf("Do not call the Stmt constructor directly.")
|
||||||
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
@ -1391,6 +1397,14 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
db.selectValue("SELECT "+Number.MIN_SAFE_INTEGER)).
|
db.selectValue("SELECT "+Number.MIN_SAFE_INTEGER)).
|
||||||
assert(Number.MAX_SAFE_INTEGER ===
|
assert(Number.MAX_SAFE_INTEGER ===
|
||||||
db.selectValue("SELECT "+Number.MAX_SAFE_INTEGER));
|
db.selectValue("SELECT "+Number.MAX_SAFE_INTEGER));
|
||||||
|
|
||||||
|
counter = 0;
|
||||||
|
db.exec({
|
||||||
|
sql: "SELECT a FROM t",
|
||||||
|
callback: ()=>(1===++counter),
|
||||||
|
});
|
||||||
|
T.assert(2===counter,
|
||||||
|
"Expecting exec step() loop to stop if callback returns false.");
|
||||||
if(wasm.bigIntEnabled && haveWasmCTests()){
|
if(wasm.bigIntEnabled && haveWasmCTests()){
|
||||||
const mI = wasm.xCall('sqlite3_wasm_test_int64_max');
|
const mI = wasm.xCall('sqlite3_wasm_test_int64_max');
|
||||||
const b = BigInt(Number.MAX_SAFE_INTEGER * 2);
|
const b = BigInt(Number.MAX_SAFE_INTEGER * 2);
|
||||||
@ -1611,6 +1625,7 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
db.createFunction("bar", {
|
db.createFunction("bar", {
|
||||||
arity: -1,
|
arity: -1,
|
||||||
xFunc: (pCx,...args)=>{
|
xFunc: (pCx,...args)=>{
|
||||||
|
T.assert(db.pointer === capi.sqlite3_context_db_handle(pCx));
|
||||||
let rc = 0;
|
let rc = 0;
|
||||||
for(const v of args) rc += v;
|
for(const v of args) rc += v;
|
||||||
return rc;
|
return rc;
|
||||||
@ -1634,7 +1649,10 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
assert(T.eqApprox(1.3,db.selectValue("select asis(1 + 0.3)")));
|
assert(T.eqApprox(1.3,db.selectValue("select asis(1 + 0.3)")));
|
||||||
|
|
||||||
let blobArg = new Uint8Array([0x68, 0x69]);
|
let blobArg = new Uint8Array([0x68, 0x69]);
|
||||||
let blobRc = db.selectValue("select asis(?1)", blobArg);
|
let blobRc = db.selectValue(
|
||||||
|
"select asis(?1)",
|
||||||
|
blobArg.buffer/*confirm that ArrayBuffer is handled as a Uint8Array*/
|
||||||
|
);
|
||||||
T.assert(blobRc instanceof Uint8Array).
|
T.assert(blobRc instanceof Uint8Array).
|
||||||
assert(2 === blobRc.length).
|
assert(2 === blobRc.length).
|
||||||
assert(0x68==blobRc[0] && 0x69==blobRc[1]);
|
assert(0x68==blobRc[0] && 0x69==blobRc[1]);
|
||||||
@ -1865,18 +1883,18 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
T.assert(3===resultRows.length)
|
T.assert(3===resultRows.length)
|
||||||
.assert(2===resultRows[1]);
|
.assert(2===resultRows[1]);
|
||||||
T.assert(2===db.selectValue('select a from foo.bar where a>1 order by a'));
|
T.assert(2===db.selectValue('select a from foo.bar where a>1 order by a'));
|
||||||
|
|
||||||
|
/** Demonstrate the JS-simplified form of the sqlite3_exec() callback... */
|
||||||
let colCount = 0, rowCount = 0;
|
let colCount = 0, rowCount = 0;
|
||||||
const execCallback = function(pVoid, nCols, aVals, aNames){
|
let rc = capi.sqlite3_exec(
|
||||||
|
db, "select a, a*2 from foo.bar", function(aVals, aNames){
|
||||||
//console.warn("execCallback(",arguments,")");
|
//console.warn("execCallback(",arguments,")");
|
||||||
colCount = nCols;
|
colCount = aVals.length;
|
||||||
++rowCount;
|
++rowCount;
|
||||||
T.assert(2===aVals.length)
|
T.assert(2===aVals.length)
|
||||||
.assert(2===aNames.length)
|
.assert(2===aNames.length)
|
||||||
.assert(+(aVals[1]) === 2 * +(aVals[0]));
|
.assert(+(aVals[1]) === 2 * +(aVals[0]));
|
||||||
};
|
}, 0, 0
|
||||||
let rc = capi.sqlite3_exec(
|
|
||||||
db.pointer, "select a, a*2 from foo.bar", execCallback,
|
|
||||||
0, 0
|
|
||||||
);
|
);
|
||||||
T.assert(0===rc).assert(3===rowCount).assert(2===colCount);
|
T.assert(0===rc).assert(3===rowCount).assert(2===colCount);
|
||||||
rc = capi.sqlite3_exec(
|
rc = capi.sqlite3_exec(
|
||||||
@ -1885,8 +1903,45 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
}, 0, 0
|
}, 0, 0
|
||||||
);
|
);
|
||||||
T.assert(capi.SQLITE_ABORT === rc);
|
T.assert(capi.SQLITE_ABORT === rc);
|
||||||
|
|
||||||
|
/* Demonstrate how to get access to the "full" callback
|
||||||
|
signature, as opposed to the simplified JS-specific one... */
|
||||||
|
rowCount = colCount = 0;
|
||||||
|
const pCb = wasm.installFunction('i(pipp)', function(pVoid,nCols,aVals,aCols){
|
||||||
|
/* Tip: wasm.cArgvToJs() can be used to convert aVals and
|
||||||
|
aCols to arrays: const vals = wasm.cArgvToJs(nCols,
|
||||||
|
aVals); */
|
||||||
|
++rowCount;
|
||||||
|
colCount = nCols;
|
||||||
|
T.assert(2 === nCols)
|
||||||
|
.assert(wasm.isPtr(pVoid))
|
||||||
|
.assert(wasm.isPtr(aVals))
|
||||||
|
.assert(wasm.isPtr(aCols))
|
||||||
|
.assert(+wasm.cstrToJs(wasm.peekPtr(aVals + wasm.ptrSizeof))
|
||||||
|
=== 2 * +wasm.cstrToJs(wasm.peekPtr(aVals)));
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
T.assert(wasm.isPtr(pCb));
|
||||||
|
rc = capi.sqlite3_exec(db, "select a, a*2 from foo.bar", pCb, 0, 0);
|
||||||
|
T.assert(0===rc)
|
||||||
|
.assert(3===rowCount)
|
||||||
|
.assert(2===colCount);
|
||||||
|
}finally{
|
||||||
|
wasm.uninstallFunction(pCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demonstrate that an OOM result does not propagate through sqlite3_exec()...
|
||||||
|
rc = capi.sqlite3_exec(
|
||||||
|
db, "select a, a*2 from foo.bar", function(aVals, aNames){
|
||||||
|
sqlite3.WasmAllocError.toss("just testing");
|
||||||
|
}, 0, 0
|
||||||
|
);
|
||||||
|
T.assert(capi.SQLITE_ABORT === rc);
|
||||||
|
|
||||||
db.exec("detach foo");
|
db.exec("detach foo");
|
||||||
T.mustThrow(()=>db.exec("select * from foo.bar"));
|
T.mustThrow(()=>db.exec("select * from foo.bar"),
|
||||||
|
"Because foo is no longer attached.");
|
||||||
})
|
})
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -1970,7 +2025,6 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
name: 'virtual table #1: eponymous w/ manual exception handling',
|
name: 'virtual table #1: eponymous w/ manual exception handling',
|
||||||
predicate: ()=>!!capi.sqlite3_index_info,
|
predicate: ()=>!!capi.sqlite3_index_info,
|
||||||
test: function(sqlite3){
|
test: function(sqlite3){
|
||||||
warn("The vtab/module JS bindings are experimental and subject to change.");
|
|
||||||
const VT = sqlite3.vtab;
|
const VT = sqlite3.vtab;
|
||||||
const tmplCols = Object.assign(Object.create(null),{
|
const tmplCols = Object.assign(Object.create(null),{
|
||||||
A: 0, B: 1
|
A: 0, B: 1
|
||||||
@ -2168,7 +2222,6 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
name: 'virtual table #2: non-eponymous w/ automated exception wrapping',
|
name: 'virtual table #2: non-eponymous w/ automated exception wrapping',
|
||||||
predicate: ()=>!!capi.sqlite3_index_info,
|
predicate: ()=>!!capi.sqlite3_index_info,
|
||||||
test: function(sqlite3){
|
test: function(sqlite3){
|
||||||
warn("The vtab/module JS bindings are experimental and subject to change.");
|
|
||||||
const VT = sqlite3.vtab;
|
const VT = sqlite3.vtab;
|
||||||
const tmplCols = Object.assign(Object.create(null),{
|
const tmplCols = Object.assign(Object.create(null),{
|
||||||
A: 0, B: 1
|
A: 0, B: 1
|
||||||
|
22
manifest
22
manifest
@ -1,5 +1,5 @@
|
|||||||
C Merge\strunk\sinto\swasm-session-api\sbranch.
|
C Merge\strunk\sinto\swasm-session-api\sbranch.
|
||||||
D 2022-12-23T21:23:26.788
|
D 2022-12-25T14:13:52.379
|
||||||
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
|
||||||
@ -494,7 +494,7 @@ F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34ce
|
|||||||
F ext/wasm/GNUmakefile ffe0e9818a3b6b36c85a1d10dab76b220a8f5cd83439c62e50223a7970b3d68a
|
F ext/wasm/GNUmakefile ffe0e9818a3b6b36c85a1d10dab76b220a8f5cd83439c62e50223a7970b3d68a
|
||||||
F ext/wasm/README-dist.txt 2d670b426fc7c613b90a7d2f2b05b433088fe65181abead970980f0a4a75ea20
|
F ext/wasm/README-dist.txt 2d670b426fc7c613b90a7d2f2b05b433088fe65181abead970980f0a4a75ea20
|
||||||
F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9
|
F ext/wasm/README.md ef39861aa21632fdbca0bdd469f78f0096f6449a720f3f39642594af503030e9
|
||||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 8c15a035ca5263659f21a691d701e23294621a24d1e130fa8905a261b495ebe4
|
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api beec6b5993e234153446aaa48e68d2a75db590b3c7eed26bd61e5fb5f8c9a881
|
||||||
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
|
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
|
||||||
F ext/wasm/api/README.md 77a2f1f2fc60a35def7455dffc8d3f2c56385d6ac5c6cecc60fa938252ea2c54
|
F ext/wasm/api/README.md 77a2f1f2fc60a35def7455dffc8d3f2c56385d6ac5c6cecc60fa938252ea2c54
|
||||||
F ext/wasm/api/extern-post-js.c-pp.js 8923f76c3d2213159e12d641dc750523ead5c848185dc4996fae5cc12397f88d
|
F ext/wasm/api/extern-post-js.c-pp.js 8923f76c3d2213159e12d641dc750523ead5c848185dc4996fae5cc12397f88d
|
||||||
@ -503,16 +503,16 @@ 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 ad1316f162fc19f92e563e9ae6794c002d0ffe6c0756f5f7e701affc7443aac0
|
F ext/wasm/api/sqlite3-api-glue.js 171657a8c758cba72d903b20b42c72a523915ca03c8d652339bf41f5f1da2f09
|
||||||
F ext/wasm/api/sqlite3-api-oo1.js 4cce9671e8a31ac9b76bd8559e7827ccc2b121734e460fa9c7d243735a771ec8
|
F ext/wasm/api/sqlite3-api-oo1.js 5393fb0b325d2fdafada7fdbfb9219af9a865631acb351d5c5196a982b632c8b
|
||||||
F ext/wasm/api/sqlite3-api-prologue.js 789639d256e3134563c5c9be25ade28b40e06e783885d26cccc01cd1ed4b820d
|
F ext/wasm/api/sqlite3-api-prologue.js 4ffe2b80742e2fcf44de6174bfb2981ff26ea0d1fe505bb511ffe0d9ac8fe6d0
|
||||||
F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f
|
F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f
|
||||||
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
|
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
|
||||||
F ext/wasm/api/sqlite3-opfs-async-proxy.js 7795b84b66a7a8dedc791340709b310bb497c3c72a80bef364fa2a58e2ddae3f
|
F ext/wasm/api/sqlite3-opfs-async-proxy.js 7795b84b66a7a8dedc791340709b310bb497c3c72a80bef364fa2a58e2ddae3f
|
||||||
F ext/wasm/api/sqlite3-v-helper.js 6f6c3e390a72e08b0a5b16a0d567d7af3c04d172831853a29d72a6f1dd40ff24
|
F ext/wasm/api/sqlite3-v-helper.js 6f6c3e390a72e08b0a5b16a0d567d7af3c04d172831853a29d72a6f1dd40ff24
|
||||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 66daf6fb6843bea615fe193109e1542efbeca24f560ee9da63375a910bb48115
|
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 66daf6fb6843bea615fe193109e1542efbeca24f560ee9da63375a910bb48115
|
||||||
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
|
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
|
||||||
F ext/wasm/api/sqlite3-wasm.c e2e8bddedd663fda5b3f7fda8d17ab229a5545a9a71cf2536282e4b2c06609ce
|
F ext/wasm/api/sqlite3-wasm.c 2bee083def8f832c863d5f0a0fcbff86c236412663c6d3458128db154c0fccc8
|
||||||
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 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
|
F ext/wasm/common/emscripten.css 11bd104b6c0d597c67d40cc8ecc0a60dae2b965151e3b6a37fa5708bac3acd15
|
||||||
F ext/wasm/common/testing.css 0ff15602a3ab2bad8aef2c3bd120c7ee3fd1c2054ad2ace7e214187ae68d926f
|
F ext/wasm/common/testing.css 0ff15602a3ab2bad8aef2c3bd120c7ee3fd1c2054ad2ace7e214187ae68d926f
|
||||||
F ext/wasm/common/whwasmutil.js e057af1aa1bd756864528b26ab26286bab3562117db550b173ffdbe867710114
|
F ext/wasm/common/whwasmutil.js 495cdffe8a6107608412ee57cdad79267f14a56e6b7825b9dc30c8ccfb02c87b
|
||||||
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
|
||||||
@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
|
|||||||
F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b
|
F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b
|
||||||
F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9
|
F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9
|
||||||
F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406
|
F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406
|
||||||
F ext/wasm/tester1.c-pp.js 50b51af2b5466de0cba8ebc97b86bc886c32f937d8f4b36d3b3936ef9748e534
|
F ext/wasm/tester1.c-pp.js 47190277040a6163716c02d11930dc4f028d44a6fcdacb10303010f239ce0a6c
|
||||||
F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70
|
F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70
|
||||||
F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
|
F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
|
||||||
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
|
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
|
||||||
@ -2067,8 +2067,8 @@ 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 f1decc831fe0dc8523956e74474d9663852b0e5b56240dd8504952726e713a97 1dfc03ab1e0269807beef27bf884ab9ead7553d4a5f6ed213f812d7fa052045f
|
P 6cdb036d8e8c5ddb0c6578aeefe318e74d7a90228e57b9f9047057dae3252963 8e3d4f6294037396e388ec21abb18bf0201a6bec6ff004730cc5d11b705a6d2b
|
||||||
R 9aa2a2dc0a7c0fcc30fe7505f3bf3c8f
|
R 81fe514e1af16b08edf276165dc4ebe1
|
||||||
U stephan
|
U stephan
|
||||||
Z 59d68c6f9d56bc64393e66c46594b9c5
|
Z 68ce3f310d94edded8b970aa4257758a
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
6cdb036d8e8c5ddb0c6578aeefe318e74d7a90228e57b9f9047057dae3252963
|
7f8f1acd82be7dc2eb2147d96299b1b443e86774dfe0b0a8d32669a0500fc9c6
|
Reference in New Issue
Block a user