mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Make semantics for UDF xFinal() result handling and error reporting handling more flexible.
FossilOrigin-Name: 89f3e1982ec32c010af67d15ef780847df20de568669e5c9d02f3cf084f51330
This commit is contained in:
@ -226,6 +226,9 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
const __udfSetResult = function(pCtx, val){
|
const __udfSetResult = function(pCtx, val){
|
||||||
//console.warn("udfSetResult",typeof val, val);
|
//console.warn("udfSetResult",typeof val, val);
|
||||||
switch(typeof val) {
|
switch(typeof val) {
|
||||||
|
case 'undefined':
|
||||||
|
/* Assume that the client already called sqlite3_result_xxx(). */
|
||||||
|
break;
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
capi.sqlite3_result_int(pCtx, val ? 1 : 0);
|
capi.sqlite3_result_int(pCtx, val ? 1 : 0);
|
||||||
break;
|
break;
|
||||||
@ -320,7 +323,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
if(e instanceof sqlite3.WasmAllocError){
|
if(e instanceof sqlite3.WasmAllocError){
|
||||||
capi.sqlite3_result_error_nomem(pCtx);
|
capi.sqlite3_result_error_nomem(pCtx);
|
||||||
}else{
|
}else{
|
||||||
capi.sqlite3_result_error(pCtx, e.message, -1);
|
const msg = ('string'===typeof e) ? e : e.message;
|
||||||
|
capi.sqlite3_result_error(pCtx, msg, -1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -462,6 +466,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
- `number`: sqlite3_result_int() or sqlite3_result_double()
|
- `number`: sqlite3_result_int() or sqlite3_result_double()
|
||||||
- `string`: sqlite3_result_text()
|
- `string`: sqlite3_result_text()
|
||||||
- Uint8Array or Int8Array: sqlite3_result_blob()
|
- Uint8Array or Int8Array: sqlite3_result_blob()
|
||||||
|
- `undefined`: indicates that the UDF called one of the
|
||||||
|
`sqlite3_result_xyz()` routines on its own, making this
|
||||||
|
function a no-op. Results are _undefined_ if this function is
|
||||||
|
passed the `undefined` value but did _not_ call one of the
|
||||||
|
`sqlite3_result_xyz()` routines.
|
||||||
|
|
||||||
Anything else triggers sqlite3_result_error().
|
Anything else triggers sqlite3_result_error().
|
||||||
*/
|
*/
|
||||||
@ -494,10 +503,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
/**
|
/**
|
||||||
A helper for UDFs implemented in JS and bound to WASM by the
|
A helper for UDFs implemented in JS and bound to WASM by the
|
||||||
client. It expects to be a passed `(sqlite3_context*, Error)`
|
client. It expects to be a passed `(sqlite3_context*, Error)`
|
||||||
(i.e. an exception object). And it sets the current UDF's
|
(an exception object or message string). And it sets the
|
||||||
result to sqlite3_result_error_nomem() or sqlite3_result_error(),
|
current UDF's result to sqlite3_result_error_nomem() or
|
||||||
depending on whether the 2nd argument is a
|
sqlite3_result_error(), depending on whether the 2nd argument
|
||||||
sqlite3.WasmAllocError object or not.
|
is a sqlite3.WasmAllocError object or not.
|
||||||
*/
|
*/
|
||||||
capi.sqlite3_create_function_v2.udfSetError =
|
capi.sqlite3_create_function_v2.udfSetError =
|
||||||
capi.sqlite3_create_function.udfSetError =
|
capi.sqlite3_create_function.udfSetError =
|
||||||
|
@ -1208,13 +1208,15 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
/**
|
/**
|
||||||
A thin wrapper around capi.sqlite3_aggregate_context() which
|
A thin wrapper around capi.sqlite3_aggregate_context() which
|
||||||
behaves the same except that it throws a WasmAllocError if that
|
behaves the same except that it throws a WasmAllocError if that
|
||||||
function returns 0.
|
function returns 0. As a special case, if n is falsy it does
|
||||||
|
_not_ throw if that function returns 0. That special case is
|
||||||
|
intended for use with xFinal() implementations.
|
||||||
*/
|
*/
|
||||||
capi.sqlite3_js_aggregate_context = (pCtx, n)=>{
|
capi.sqlite3_js_aggregate_context = (pCtx, n)=>{
|
||||||
return capi.sqlite3_aggregate_context(pCtx, n)
|
return capi.sqlite3_aggregate_context(pCtx, n)
|
||||||
|| WasmAllocError.toss(
|
|| (n ? WasmAllocError.toss("Cannot allocate",n,
|
||||||
"Cannot allocate",n,"bytes for sqlite3_aggregate_context()"
|
"bytes for sqlite3_aggregate_context()")
|
||||||
);
|
: 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
if( capi.util.isMainWindow() ){
|
if( capi.util.isMainWindow() ){
|
||||||
|
@ -43,44 +43,46 @@
|
|||||||
const isWorker = ()=>!isUIThread();
|
const isWorker = ()=>!isUIThread();
|
||||||
/* Predicate for tests/groups. */
|
/* Predicate for tests/groups. */
|
||||||
const testIsTodo = ()=>false;
|
const testIsTodo = ()=>false;
|
||||||
const haveWasmCTests = function(){
|
const haveWasmCTests = ()=>{
|
||||||
return !!wasm.exports.sqlite3_wasm_test_int64_max;
|
return !!wasm.exports.sqlite3_wasm_test_int64_max;
|
||||||
};
|
};
|
||||||
const mapToString = (v)=>{
|
{
|
||||||
switch(typeof v){
|
const mapToString = (v)=>{
|
||||||
case 'number': case 'string': case 'boolean':
|
switch(typeof v){
|
||||||
case 'undefined':
|
case 'number': case 'string': case 'boolean':
|
||||||
return ''+v;
|
case 'undefined':
|
||||||
default: break;
|
return ''+v;
|
||||||
}
|
default: break;
|
||||||
if(null===v) return 'null';
|
}
|
||||||
if(v instanceof Error){
|
if(null===v) return 'null';
|
||||||
v = {
|
if(v instanceof Error){
|
||||||
message: v.message,
|
v = {
|
||||||
stack: v.stack,
|
message: v.message,
|
||||||
errorClass: v.name
|
stack: v.stack,
|
||||||
|
errorClass: v.name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return JSON.stringify(v,undefined,2);
|
||||||
|
};
|
||||||
|
const normalizeArgs = (args)=>args.map(mapToString);
|
||||||
|
if( isUIThread() ){
|
||||||
|
console.log("Running in the UI thread.");
|
||||||
|
const logTarget = document.querySelector('#test-output');
|
||||||
|
logClass = function(cssClass,...args){
|
||||||
|
const ln = document.createElement('div');
|
||||||
|
if(cssClass) ln.classList.add(cssClass);
|
||||||
|
ln.append(document.createTextNode(normalizeArgs(args).join(' ')));
|
||||||
|
logTarget.append(ln);
|
||||||
|
};
|
||||||
|
}else{ /* Worker thread */
|
||||||
|
console.log("Running in a Worker thread.");
|
||||||
|
logClass = function(cssClass,...args){
|
||||||
|
postMessage({
|
||||||
|
type:'log',
|
||||||
|
payload:{cssClass, args: normalizeArgs(args)}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return JSON.stringify(v,undefined,2);
|
|
||||||
};
|
|
||||||
const normalizeArgs = (args)=>args.map(mapToString);
|
|
||||||
if( isUIThread() ){
|
|
||||||
console.log("Running in the UI thread.");
|
|
||||||
const logTarget = document.querySelector('#test-output');
|
|
||||||
logClass = function(cssClass,...args){
|
|
||||||
const ln = document.createElement('div');
|
|
||||||
if(cssClass) ln.classList.add(cssClass);
|
|
||||||
ln.append(document.createTextNode(normalizeArgs(args).join(' ')));
|
|
||||||
logTarget.append(ln);
|
|
||||||
};
|
|
||||||
}else{ /* Worker thread */
|
|
||||||
console.log("Running in a Worker thread.");
|
|
||||||
logClass = function(cssClass,...args){
|
|
||||||
postMessage({
|
|
||||||
type:'log',
|
|
||||||
payload:{cssClass, args: normalizeArgs(args)}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
const log = (...args)=>{
|
const log = (...args)=>{
|
||||||
//console.log(...args);
|
//console.log(...args);
|
||||||
@ -1281,10 +1283,13 @@
|
|||||||
db.createFunction({
|
db.createFunction({
|
||||||
name: 'summer',
|
name: 'summer',
|
||||||
xStep: function(pCtx, n){
|
xStep: function(pCtx, n){
|
||||||
const pAgg = sjac(pCtx, 4);
|
const ac = sjac(pCtx, 4);
|
||||||
wasm.setMemValue(pAgg, wasm.getMemValue(pAgg,'i32') + Number(n), 'i32');
|
wasm.setMemValue(ac, wasm.getMemValue(ac,'i32') + Number(n), 'i32');
|
||||||
},
|
},
|
||||||
xFinal: (pCtx)=>wasm.getMemValue(sjac(pCtx, 4),'i32')
|
xFinal: (pCtx)=>{
|
||||||
|
const ac = sjac(pCtx, 0);
|
||||||
|
return ac ? wasm.getMemValue(ac,'i32') : 0;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
let v = db.selectValue([
|
let v = db.selectValue([
|
||||||
"with cte(v) as (",
|
"with cte(v) as (",
|
||||||
@ -1306,8 +1311,12 @@
|
|||||||
for(const v of args) sum += Number(v);
|
for(const v of args) sum += Number(v);
|
||||||
wasm.setMemValue(pAgg, sum, 'i32');
|
wasm.setMemValue(pAgg, sum, 'i32');
|
||||||
},
|
},
|
||||||
xFinal: function(pCtx){
|
xFinal: (pCtx)=>{
|
||||||
return wasm.getMemValue(sjac(pCtx, 4),'i32')
|
const ac = sjac(pCtx, 0);
|
||||||
|
capi.sqlite3_result_int( pCtx, ac ? wasm.getMemValue(ac,'i32') : 0 );
|
||||||
|
// xFinal() may either return its value directly or call
|
||||||
|
// sqlite3_result_xyz() and return undefined. Both are
|
||||||
|
// functionally equivalent.
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
T.assert(18===db.selectValue('select summerN(1,8,9), summerN(2,3,4)'));
|
T.assert(18===db.selectValue('select summerN(1,8,9), summerN(2,3,4)'));
|
||||||
@ -1347,7 +1356,10 @@
|
|||||||
const pAgg = sjac(pCtx, 8);
|
const pAgg = sjac(pCtx, 8);
|
||||||
wasm.setMemValue(pAgg, wasm.getMemValue(pAgg,'i64') + BigInt(n), 'i64');
|
wasm.setMemValue(pAgg, wasm.getMemValue(pAgg,'i64') + BigInt(n), 'i64');
|
||||||
},
|
},
|
||||||
xFinal: (pCtx)=>wasm.getMemValue(sjac(pCtx, 8),'i64')
|
xFinal: (pCtx)=>{
|
||||||
|
const ac = sjac(pCtx, 0);
|
||||||
|
return ac ? wasm.getMemValue(ac,'i64') : 0n;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
let v = db.selectValue([
|
let v = db.selectValue([
|
||||||
"with cte(v) as (",
|
"with cte(v) as (",
|
||||||
|
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
|||||||
C Add\smore\sJS\stests.\sFlesh\sout\sthe\saggregate\sUDF\stests\sto\suse\ssqlite3_aggregate_context()\sso\sthat\sthey\scan\seach\sbe\sused\smultiple\stimes\sin\sthe\ssame\sstatement.\sAdd\ssqlite3_js_aggregate_context()\sconvenience\shelper.
|
C Make\ssemantics\sfor\sUDF\sxFinal()\sresult\shandling\sand\serror\sreporting\shandling\smore\sflexible.
|
||||||
D 2022-10-20T21:28:31.440
|
D 2022-10-20T23:48:38.866
|
||||||
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
|
||||||
@ -484,10 +484,10 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08
|
|||||||
F ext/wasm/api/post-js-header.js 2e5c886398013ba2af88028ecbced1e4b22dc96a86467f1ecc5ba9e64ef90a8b
|
F ext/wasm/api/post-js-header.js 2e5c886398013ba2af88028ecbced1e4b22dc96a86467f1ecc5ba9e64ef90a8b
|
||||||
F ext/wasm/api/pre-js.js 151e0616614a49f3db19ed544fa13b38c87c108959fbcd4029ea8399a562d94f
|
F ext/wasm/api/pre-js.js 151e0616614a49f3db19ed544fa13b38c87c108959fbcd4029ea8399a562d94f
|
||||||
F ext/wasm/api/sqlite3-api-cleanup.js 4d07a7524dc9b7b050acfde57163e839243ad2383bd7ee0de0178b1b3e988588
|
F ext/wasm/api/sqlite3-api-cleanup.js 4d07a7524dc9b7b050acfde57163e839243ad2383bd7ee0de0178b1b3e988588
|
||||||
F ext/wasm/api/sqlite3-api-glue.js 0b5240bd325d2561f269cd0d82bf686336526e5e276251c2241adfbda802abf8
|
F ext/wasm/api/sqlite3-api-glue.js ea760df5991cee48e29aa6ced503027760462d5696d50521f7273a91e0e1430c
|
||||||
F ext/wasm/api/sqlite3-api-oo1.js 0e278d131dad72e9eb348a3dda6a4ff734a9e08925b4ed7e6e5a688d2edaf525
|
F ext/wasm/api/sqlite3-api-oo1.js 0e278d131dad72e9eb348a3dda6a4ff734a9e08925b4ed7e6e5a688d2edaf525
|
||||||
F ext/wasm/api/sqlite3-api-opfs.js 22d60ba956e873b65e2e0591e239178082bd53a6d563c3c58db7dc03e562e8f7
|
F ext/wasm/api/sqlite3-api-opfs.js 22d60ba956e873b65e2e0591e239178082bd53a6d563c3c58db7dc03e562e8f7
|
||||||
F ext/wasm/api/sqlite3-api-prologue.js bb7a98a8c62545bf07b5fdee831c0d40c86f98c0094b00d8497a9de8976a0544
|
F ext/wasm/api/sqlite3-api-prologue.js e4fbfa66eb6c5c544c52dea6cb48051eddcdc21c276c39a80801f5e76e6c5b56
|
||||||
F ext/wasm/api/sqlite3-api-worker1.js a7f38f03275d6c27ab2aef3e83215d3c97ce09c43e6904df47c3764d9d4572b4
|
F ext/wasm/api/sqlite3-api-worker1.js a7f38f03275d6c27ab2aef3e83215d3c97ce09c43e6904df47c3764d9d4572b4
|
||||||
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 206ce6bbc3c30ad51a37d9c25e3a2712e70b586e0f9a2cf8cb0b9619017c2671
|
F ext/wasm/api/sqlite3-opfs-async-proxy.js 206ce6bbc3c30ad51a37d9c25e3a2712e70b586e0f9a2cf8cb0b9619017c2671
|
||||||
@ -533,7 +533,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
|
|||||||
F ext/wasm/test-opfs-vfs.js 48fc59110e8775bb43c9be25b6d634fc07ebadab7da8fbd44889e8129c6e2548
|
F ext/wasm/test-opfs-vfs.js 48fc59110e8775bb43c9be25b6d634fc07ebadab7da8fbd44889e8129c6e2548
|
||||||
F ext/wasm/tester1-worker.html 048c341f124fdb61ca14dfd1bd1f78742490f208aa3bb1e84399f83f1e7e6a74
|
F ext/wasm/tester1-worker.html 048c341f124fdb61ca14dfd1bd1f78742490f208aa3bb1e84399f83f1e7e6a74
|
||||||
F ext/wasm/tester1.html 37ccc958fa0d95074af2d72b7241c8e2d982bbec6dda4dc790241af3d933c3b6
|
F ext/wasm/tester1.html 37ccc958fa0d95074af2d72b7241c8e2d982bbec6dda4dc790241af3d933c3b6
|
||||||
F ext/wasm/tester1.js 6e1c8e4d48add1d49fb7901dfee04fdf6cdd5bc39adcbf15c097f61b581a893c
|
F ext/wasm/tester1.js 5533cd100dc663dbe548fb04aefc490aa4b3d2e0ec2212f79881bb4893266e39
|
||||||
F ext/wasm/version-info.c 5fa356d38859d71a0369b5c37e1935def7413fcc8a4e349a39d9052c1d0479f4
|
F ext/wasm/version-info.c 5fa356d38859d71a0369b5c37e1935def7413fcc8a4e349a39d9052c1d0479f4
|
||||||
F ext/wasm/wasmfs.make ee0004813e16c283ff633e08b482008d56adf9b7d42f6c5612f7ab002b924f69
|
F ext/wasm/wasmfs.make ee0004813e16c283ff633e08b482008d56adf9b7d42f6c5612f7ab002b924f69
|
||||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||||
@ -2036,8 +2036,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 9bf26e2aa3579f354ed2d314e1bf3e3ef117cbd71500ef5f76caa1de5cce1edc
|
P 9d034ef5e1bab7c9651c2450dc85765fa6365d3f1414c711550de858ff8b3ece
|
||||||
R dbe97bbb80fe6071199461fb846ef1aa
|
R dfb3978c0632c8b69ab9fb0976c9a2ee
|
||||||
U stephan
|
U stephan
|
||||||
Z 83bd13decfea9b8d2129079a8ff06725
|
Z c86f3e45c75ca0a38f433f4183ca8f53
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
9d034ef5e1bab7c9651c2450dc85765fa6365d3f1414c711550de858ff8b3ece
|
89f3e1982ec32c010af67d15ef780847df20de568669e5c9d02f3cf084f51330
|
Reference in New Issue
Block a user