1
0
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:
stephan
2022-12-25 14:13:52 +00:00
9 changed files with 670 additions and 409 deletions

View File

@ -24,6 +24,33 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
self.WhWasmUtilInstaller(wasm);
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
is an array with 2+ elements:
@ -42,10 +69,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
wasm.bindingSignatures = [
// Please keep these sorted by function name!
["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*"
/* TODO: we should arguably write a custom wrapper which knows
how to handle Blob, TypedArrays, and JS strings. */
],
/* sqlite3_bind_blob() and sqlite3_bind_text() have hand-written
bindings to permit more flexible inputs. */
["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "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_pointer", "int",
"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*",
new wasm.xWrap.FuncPtrAdapter({
name: 'sqlite3_busy_handler',
signature: 'i(pi)',
bindScope: 'context',
contextKey: (argIndex,argv)=>'sqlite3@'+argv[0]
contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
}),
"*"
]],
@ -86,6 +103,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["sqlite3_compileoption_get", "string", "int"],
["sqlite3_compileoption_used", "int", "string"],
["sqlite3_complete", "int", "string:flexible"],
["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"],
/* sqlite3_create_function(), sqlite3_create_function_v2(), and
sqlite3_create_window_function() use hand-written bindings to
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. */
/* sqlite3_randomness() uses a hand-written wrapper to extend
the range of supported argument types. */
[
"sqlite3_progress_handler", undefined, [
"sqlite3*", "int",
new wasm.xWrap.FuncPtrAdapter({
name: 'xProgressHandler',
signature: 'i(p)',
bindScope: 'context',
contextKey: (argIndex,argv)=>'sqlite3@'+argv[0]
}),
"*"
]
],
["sqlite3_progress_handler", undefined, [
"sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({
name: 'xProgressHandler',
signature: 'i(p)',
bindScope: 'context',
contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
}), "*"
]],
["sqlite3_realloc", "*","*","int"],
["sqlite3_reset", "int", "sqlite3_stmt*"],
["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_text", undefined, "sqlite3_context*", "string", "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_sourceid", "string"],
["sqlite3_sql", "string", "sqlite3_stmt*"],
@ -181,12 +223,15 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
"sqlite3*", "string", "string", "string",
"**", "**", "*", "*", "*"],
["sqlite3_total_changes", "int", "sqlite3*"],
["sqlite3_trace_v2", "int", "sqlite3*", "int",
new wasm.xWrap.FuncPtrAdapter({
name: 'sqlite3_trace_v2::callback',
signature: 'i(ippp)',
contextKey: (argIndex, argv)=>'sqlite3@'+argv[0]
}), "*"],
["sqlite3_trace_v2", "int", [
"sqlite3*", "int",
new wasm.xWrap.FuncPtrAdapter({
name: 'sqlite3_trace_v2::callback',
signature: 'i(ippp)',
contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
}),
"*"
]],
["sqlite3_txn_state", "int", ["sqlite3*","string"]],
/* Note that sqlite3_uri_...() have very specific requirements for
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_zeroblob64", "int", "*", "i64"],
["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_status64", "int", "int", "*", "*", "int"],
["sqlite3_total_changes64", "i64", ["sqlite3*"]],
@ -667,28 +710,24 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
);
};
if(1){/* Bindings for sqlite3_create_collation[_v2]() */
const __collationContextKey = (argIndex,argv)=>{
return 'argv['+argIndex+']:sqlite3@'+argv[0]+
':'+wasm.cstrToJs(argv[1]).toLowerCase()
{/* Bindings for sqlite3_create_collation[_v2]() */
// contextKey() impl for wasm.xWrap.FuncPtrAdapter
const contextKey = (argv,argIndex)=>{
return 'argv['+argIndex+']:'+argv[0/* sqlite3* */]+
':'+wasm.cstrToJs(argv[1/* collation name */]).toLowerCase()
};
const __ccv2 = wasm.xWrap(
'sqlite3_create_collation_v2', 'int',
'sqlite3*','string','int','*',
new wasm.xWrap.FuncPtrAdapter({
/* int(*xCompare)(void*,int,const void*,int,const void*) */
name: 'sqlite3_create_collation_v2::xCompare',
signature: 'i(pipip)',
bindScope: 'context',
contextKey: __collationContextKey
}),
new wasm.xWrap.FuncPtrAdapter({
/* void(*xDestroy(void*) */
name: 'sqlite3_create_collation_v2::xDestroy',
signature: 'v(p)',
bindScope: 'context',
contextKey: __collationContextKey
})
const __sqlite3CreateCollationV2 = wasm.xWrap(
'sqlite3_create_collation_v2', 'int', [
'sqlite3*', 'string', 'int', '*',
new wasm.xWrap.FuncPtrAdapter({
/* int(*xCompare)(void*,int,const void*,int,const void*) */
name: 'xCompare', signature: 'i(pipip)', contextKey
}),
new wasm.xWrap.FuncPtrAdapter({
/* void(*xDestroy(void*) */
name: 'xDestroy', signature: 'v(p)', contextKey
})
]
);
/**
@ -722,13 +761,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
return __errEncoding(pDb);
}
let rc, pfCompare, pfDestroy;
try{
rc = __ccv2(pDb, zName, eTextRep, pArg, xCompare, xDestroy);
return __sqlite3CreateCollationV2(pDb, zName, eTextRep, pArg, xCompare, xDestroy);
}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)=>{
@ -739,7 +776,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}/*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",
["sqlite3*", "string:flexible",
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
`(char**)` arguments to arrays of strings... */
let aNames;
const cbwrap = function(pVoid, nCols, pColVals, pColNames){
let rc = capi.SQLITE_ERROR;
try {
let aVals = [], aNames = [], i = 0, offset = 0;
for( ; i < nCols; offset += (wasm.ptrSizeof * ++i) ){
aVals.push( wasm.cstrToJs(wasm.peekPtr(pColVals + offset)) );
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. */
const aVals = wasm.cArgvToJs(nCols, pColVals);
if(!aNames) aNames = wasm.cArgvToJs(nCols, pColNames);
return callback(aVals, aNames) | 0;
}catch(e){
/* If we set the db error state here, the higher-level exec() call
replaces it with its own, so we have no way of reporting the
exception message except the console. We must not propagate
exceptions through the C API. */
/* If we set the db error state here, the higher-level
exec() call replaces it with its own, so we have no way
of reporting the exception message except the console. We
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;
try{
@ -786,83 +819,92 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
}/*sqlite3_exec() proxy*/;
if(1){/* Special-case handling of sqlite3_create_function_v2()
and sqlite3_create_window_function() */
/* Maintenance reminder: FuncPtrAdapter is not expressive enough
to be able to perform these mappings. */
const sqlite3CreateFunction = wasm.xWrap(
"sqlite3_create_function_v2", "int",
["sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
"int"/*eTextRep*/, "*"/*pApp*/,
"*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/, "*"/*xDestroy*/]
);
{/* Special-case handling of sqlite3_create_function_v2()
and sqlite3_create_window_function(). */
/**
FuncPtrAdapter for contextKey() for sqlite3_create_function().
*/
const contextKey = function(argv,argIndex){
return (
argv[0/* sqlite3* */]
+':'+argIndex
+':'+wasm.cstrToJs(argv[1]).toLowerCase()
)
};
const sqlite3CreateWindowFunction = wasm.xWrap(
"sqlite3_create_window_function", "int",
["sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
"int"/*eTextRep*/, "*"/*pApp*/,
"*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/,
"*"/*xInverse*/, "*"/*xDestroy*/]
);
const __xFunc = function(callback){
return function(pCtx, argc, pArgv){
try{
capi.sqlite3_result_js(
pCtx,
callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv))
);
}catch(e){
//console.error('xFunc() caught:',e);
capi.sqlite3_result_error_js(pCtx, e);
/**
JS proxies for the various sqlite3_create[_window]_function()
callbacks, structured in a form usable by wasm.xWrap.FuncPtrAdapter.
*/
const __cfProxy = Object.assign(Object.create(null), {
xInverseAndStep: {
signature:'v(pip)', contextKey,
callProxy: (callback)=>{
return (pCtx, argc, pArgv)=>{
try{ callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) }
catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
};
}
};
};
const __xInverseAndStep = function(callback){
return function(pCtx, argc, pArgv){
try{ callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) }
catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
};
};
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) }
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);
},
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{
capi.sqlite3_result_js(
pCtx,
callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv))
);
}catch(e){
//console.error('xFunc() caught:',e);
capi.sqlite3_result_error_js(pCtx, e);
}
};
}
},
xDestroy: {
signature:'v(p)', contextKey,
//Arguable: a well-behaved destructor doesn't require a proxy.
callProxy: (callback)=>{
return (pVoid)=>{
try{ callback(pVoid) }
catch(e){ console.error("UDF xDestroy method threw:",e) }
};
}
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. */
capi.sqlite3_create_function_v2 = function f(
@ -879,26 +921,16 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
return __errEncoding(pDb);
}
/* Wrap the callbacks in a WASM-bound functions... */
const uninstall = [/*funcs to uninstall on error*/];
let rc;
try{
const funcArgs = __xWrapFuncs(['xFunc','xStep','xFinal','xDestroy'],
{xFunc, xStep, xFinal, xDestroy},
uninstall);
rc = sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
pApp, ...funcArgs);
return __sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
pApp, xFunc, xStep, xFinal, xDestroy);
}catch(e){
console.error("sqlite3_create_function_v2() setup threw:",e);
for(let v of uninstall){
wasm.uninstallFunction(v);
}
rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR,
"Creation of UDF threw: "+e.message);
return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
}
return rc;
};
/* Documented in the api object's initializer. */
capi.sqlite3_create_function = function f(
pDb, funcName, nArg, eTextRep, pApp,
xFunc, xStep, xFinal
@ -914,8 +946,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
pDb, funcName, nArg, eTextRep, pApp,
xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
xFinal, //void (*xFinal)(sqlite3_context*)
xValue, //void (*xFinal)(sqlite3_context*)
xInverse,//void (*xStep)(sqlite3_context*,int,sqlite3_value**)
xValue, //void (*xValue)(sqlite3_context*)
xInverse,//void (*xInverse)(sqlite3_context*,int,sqlite3_value**)
xDestroy //void (*xDestroy)(void*)
){
if( f.length!==arguments.length ){
@ -925,24 +957,14 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
return __errEncoding(pDb);
}
/* Wrap the callbacks in a WASM-bound functions... */
const uninstall = [/*funcs to uninstall on error*/];
let rc;
try{
const funcArgs = __xWrapFuncs(['xStep','xFinal','xValue','xInverse','xDestroy'],
{xStep, xFinal, xValue, xInverse, xDestroy},
uninstall);
rc = sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep,
pApp, ...funcArgs);
return __sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep,
pApp, xStep, xFinal, xValue,
xInverse, xDestroy);
}catch(e){
console.error("sqlite3_create_window_function() setup threw:",e);
for(let v of uninstall){
wasm.uninstallFunction(v);
}
rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR,
"Creation of UDF threw: "+e.message);
return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
}
return rc;
};
/**
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
sqlite3_prepare_v3() */
/**
Helper for string:flexible conversions which require a
byte-length counterpart argument. Passed a value and its
@ -995,32 +1018,33 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
Scope-local holder of the two impls of sqlite3_prepare_v2/v3().
*/
const __prepare = Object.create(null);
/**
This binding expects a JS string as its 2nd argument and
null as its final argument. In order to compile multiple
statements from a single string, the "full" impl (see
below) must be used.
*/
__prepare.basic = wasm.xWrap('sqlite3_prepare_v3',
"int", ["sqlite3*", "string",
"int"/*ignored for this impl!*/,
"int", "**",
"**"/*MUST be 0 or null or undefined!*/]);
/**
Impl which requires that the 2nd argument be a pointer
to the SQL string, instead of being converted to a
string. This variant is necessary for cases where we
require a non-NULL value for the final argument
(exec()'ing multiple statements from one input
string). For simpler cases, where only the first
statement in the SQL string is required, the wrapper
named sqlite3_prepare_v2() is sufficient and easier to
use because it doesn't require dealing with pointers.
*/
__prepare.full = wasm.xWrap('sqlite3_prepare_v3',
"int", ["sqlite3*", "*", "int", "int",
"**", "**"]);
const __prepare = {
/**
This binding expects a JS string as its 2nd argument and
null as its final argument. In order to compile multiple
statements from a single string, the "full" impl (see
below) must be used.
*/
basic: wasm.xWrap('sqlite3_prepare_v3',
"int", ["sqlite3*", "string",
"int"/*ignored for this impl!*/,
"int", "**",
"**"/*MUST be 0 or null or undefined!*/]),
/**
Impl which requires that the 2nd argument be a pointer
to the SQL string, instead of being converted to a
string. This variant is necessary for cases where we
require a non-NULL value for the final argument
(exec()'ing multiple statements from one input
string). For simpler cases, where only the first
statement in the SQL string is required, the wrapper
named sqlite3_prepare_v2() is sufficient and easier to
use because it doesn't require dealing with pointers.
*/
full: wasm.xWrap('sqlite3_prepare_v3',
"int", ["sqlite3*", "*", "int", "int",
"**", "**"])
};
/* Documented in the capi object's initializer. */
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)
: __dbArgcMismatch(pDb,"sqlite3_prepare_v2",f.length);
};
}/*sqlite3_prepare_v2/v3()*/;
{/* sqlite3_set_authorizer() */
const __ssa = wasm.xWrap("sqlite3_set_authorizer", 'int', [
"sqlite3*",
new wasm.xWrap.FuncPtrAdapter({
name: "sqlite3_set_authorizer::xAuth",
signature: "i(pi"+"ssss)",
contextKey: (argIndex, argv)=>argv[0/*(sqlite3*)*/]
}),
"*"
}/*sqlite3_prepare_v2/v3()*/
{/*sqlite3_bind_text/blob()*/
const __bindText = wasm.xWrap("sqlite3_bind_text", "int", [
"sqlite3_stmt*", "int", "string", "int", "*"
]);
capi.sqlite3_set_authorizer = function(pDb, xAuth, pUserData){
if(3!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_set_authorizer', 3);
if(xAuth instanceof Function){
const xProxy = xAuth;
/* Create a proxy which will receive the C-strings from WASM
and convert them to JS strings for the client-supplied
function. */
xAuth = function(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 xProxy(pV, iCode, s0, s1, s2, s3) || 0;
}catch(e){
return util.sqlite3_wasm_db_error(pDb, e);
}
};
const __bindBlob = wasm.xWrap("sqlite3_bind_blob", "int", [
"sqlite3_stmt*", "int", "*", "int", "*"
]);
/** Documented in the capi object's initializer. */
capi.sqlite3_bind_text = function f(pStmt, iCol, text, nText, xDestroy){
if(f.length!==arguments.length){
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('');
}
return __ssa(pDb, xAuth, pUserData);
};
}/* sqlite3_set_authorizer() */
let p, n;
try{
if(util.isSQLableTypedArray(text)){
p = wasm.allocFromTypedArray(text);
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){
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('');
}
let p, n;
try{
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() */
/**
@ -1130,8 +1202,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
toss("Maintenance required: increase sqlite3_wasm_enum_json()'s",
"static buffer size!");
}
wasm.ctype = JSON.parse(wasm.cstrToJs(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',
'blobFinalizers', 'changeset',
'config', 'dataTypes',
@ -1139,13 +1212,12 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
'encodings', 'fcntl', 'flock', 'ioCap',
'limits', 'openFlags',
'prepareFlags', 'resultCodes',
'serialize', 'session',
'sqlite3Status',
'stmtStatus', 'syncFlags',
'trace', 'txnState', 'udfFlags',
'version' ];
if(wasm.bigIntEnabled){
defineGroups.push('vtab');
defineGroups.push('serialize', 'session', 'vtab');
}
for(const t of defineGroups){
for(const e of Object.entries(wasm.ctype[t])){
@ -1297,4 +1369,5 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
}/*pKvvfs*/
wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
});