1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-27 20:41:58 +03:00

Change DB.exec() rowMode default from 'stmt' to 'array', per /chat discussion. Add DB.exec() rowMode option for fetching a specific column by name. Add result column names to worker1 exec() callback interface, as there's otherwise no way to get that info from a worker.

FossilOrigin-Name: 1bb37e5c477b9eb098362f74a45a55be23d450fe45cdff58c1cbff08b5b3998f
This commit is contained in:
stephan
2022-08-24 20:57:37 +00:00
parent 3734401a95
commit 407f75378e
6 changed files with 139 additions and 67 deletions

View File

@ -236,14 +236,14 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
if(out.opt.callback || out.opt.resultRows){
switch((undefined===out.opt.rowMode)
? 'stmt' : out.opt.rowMode) {
? 'array' : out.opt.rowMode) {
case 'object': out.cbArg = (stmt)=>stmt.get({}); break;
case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
case 'stmt':
if(Array.isArray(out.opt.resultRows)){
toss3("Invalid rowMode for resultRows array: must",
toss3("Invalid rowMode for a resultRows array: must",
"be one of 'array', 'object',",
"or a result column number.");
"a result column number, or column name reference.");
}
out.cbArg = (stmt)=>stmt;
break;
@ -251,22 +251,16 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if(util.isInt32(out.opt.rowMode)){
out.cbArg = (stmt)=>stmt.get(out.opt.rowMode);
break;
}
/*
TODO?: how can we define rowMode such that it uses
rowMode of 'object' and returns a given named field from
the object. Something like:
if(?what goes here?){
out.cbArg = function f(stmt){return stmt.get(this.obj)[this.colName]}
.bind({obj:{}, colName: ???what goes here???}});
}else if('string'===typeof out.opt.rowMode && out.opt.rowMode.length>1){
/* "$X", ":X", and "@X" fetch column named "X" (case-sensitive!) */
const prefix = out.opt.rowMode[0];
if(':'===prefix || '@'===prefix || '$'===prefix){
out.cbArg = function(stmt){
return stmt.get(this.obj)[this.colName];
}.bind({obj:{}, colName: out.opt.rowMode.substr(1)})
break;
}
Maybe rowMode:['colName1',... 'colNameN']? That could be
ambiguous: might mean "return an object with just these
columns".
*/
}
toss3("Invalid rowMode:",out.opt.rowMode);
}
}
@ -449,7 +443,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if(rowTarget) rowTarget.push(row);
if(opt.callback){
stmt._isLocked = true;
opt.callback(row, stmt);
opt.callback(row,stmt);
stmt._isLocked = false;
}
}
@ -494,23 +488,40 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if that statement has any result _rows_. The callback's "this"
is the options object. The second argument passed to the
callback is always the current Stmt object (so that the caller
may collect column names, or similar). The first argument
passed to the callback defaults to the current Stmt object but
may be changed with ...
may collect column names, or similar). The 2nd argument to the
callback is always the Stmt instance, as it's needed if the
caller wants to fetch the column names or some such. The first
argument passed to the callback defaults to the current Stmt
object but may be changed with ...
- .rowMode = either a string describing what type of argument
should be passed as the first argument to the callback or an
integer representing a result column index. A `rowMode` of
'object' causes the results of `stmt.get({})` to be passed to
the `callback` and/or appended to `resultRows`. A value of
'array' causes the results of `stmt.get([])` to be passed to
passed on. A value of 'stmt' is equivalent to the default,
passing the current Stmt to the callback (noting that it's
always passed as the 2nd argument), but this mode will trigger
an exception if `resultRows` is an array. If `rowMode` is an
integer, only the single value from that result column will be
passed on. Any other value for the option triggers an
exception.
- .rowMode = may take one of several forms:
A) If `rowMode` is an integer, only the single value from that
result column (0-based) will be passed on.
B) A string describing what type of argument should be passed
as the first argument to the callback:
B.1) 'array' (the default) causes the results of
`stmt.get([])` to be passed to passed on and/or appended to
`resultRows`.
B.2) 'object' causes the results of `stmt.get({})` to be
passed to the `callback` and/or appended to `resultRows`.
B.3) 'stmt' causes the current Stmt to be passed to the
callback, but this mode will trigger an exception if
`resultRows` is an array because appending the statement to
the array would be unhelpful.
C) A string with a minimum length of 2 and leading character of
':', '$', or '@' will fetch the row as an object, extract that
one field, and pass that field's value to the callback. Note
that these keys are case-sensitive so must match the case used
in the SQL. e.g. `"select a A from t"` with a `rowMode` of '$A'
would work but '$a' would not (it would result in `undefined`).
Any other `rowMode` value triggers an exception.
- .resultRows: if this is an array, it functions similarly to
the `callback` option: each row of the result set (if any) of
@ -584,7 +595,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false);
wasm.setMemValue(pSql + sqlByteLen, 0/*NUL terminator*/);
while(wasm.getMemValue(pSql, 'i8')
/* Maintenance reminder: ^^^^ _must_ be i8 or else we
/* Maintenance reminder:^^^ _must_ be 'i8' or else we
will very likely cause an endless loop. What that's
doing is checking for a terminating NUL byte. If we
use i32 or similar then we read 4 bytes, read stuff
@ -615,7 +626,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
stmt._isLocked = true;
const row = arg.cbArg(stmt);
if(resultRows) resultRows.push(row);
if(callback) callback(row, stmt);
if(callback) callback(row,stmt);
stmt._isLocked = false;
}
rowMode = undefined;