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

Add sqlite3.oo1.DB.selectValues(). Correct a logic error which could cause DB.selectValue(), DB.selectArray(), and DB.selectObject() to fail to finalize a statement if a call to bind() failed. Add more session API tests.

FossilOrigin-Name: 6adc8a10146190037d55d3328d2f78aa5233559f88d4aa70fbbf9e10145b9b6c
This commit is contained in:
stephan
2022-12-25 22:44:13 +00:00
parent 3caf13f1cb
commit 9f1adb8c12
4 changed files with 109 additions and 38 deletions

View File

@ -463,22 +463,20 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
};
/**
Internal impl of the DB.selectArray() and
Internal impl of the DB.selectValue(), selectArray(), and
selectObject() methods.
*/
const __selectFirstRow = (db, sql, bind, getArg)=>{
let stmt, rc;
const __selectFirstRow = (db, sql, bind, ...getArgs)=>{
const stmt = db.prepare(sql);
try {
stmt = db.prepare(sql).bind(bind);
if(stmt.step()) rc = stmt.get(getArg);
return stmt.bind(bind).step() ? stmt.get(...getArgs) : undefined;
}finally{
if(stmt) stmt.finalize();
stmt.finalize();
}
return rc;
};
/**
Internal impl of the DB.selectArrays() and
Internal impl of the DB.selectvalues(), selectArrays(), and
selectObjects() methods.
*/
const __selectAll =
@ -1083,15 +1081,31 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
Throws on error (e.g. malformed SQL).
*/
selectValue: function(sql,bind,asType){
let stmt, rc;
return __selectFirstRow(this, sql, bind, 0, asType);
},
/**
Runs the given query and returns an array of the values from
the first result column of each row of the result set. The 2nd
argument is an optional value for use in a single-argument call
to Stmt.bind(). The 3rd argument may be any value suitable for
use as the 2nd argument to Stmt.get(). If a 3rd argument is
desired but no bind data are needed, pass `undefined` for the 2nd
argument.
If there are no result rows, an empty array is returned.
*/
selectValues: function(sql,bind,asType){
const stmt = this.prepare(sql), rc = [];
try {
stmt = this.prepare(sql).bind(bind);
if(stmt.step()) rc = stmt.get(0,asType);
stmt.bind(bind);
while(stmt.step()) rc.push(stmt.get(0,asType));
}finally{
if(stmt) stmt.finalize();
stmt.finalize();
}
return rc;
},
/**
Prepares the given SQL, step()s it one time, and returns an
array containing the values of the first result row. If it has
@ -1147,7 +1161,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
Returns the number of currently-opened Stmt handles for this db
handle, or 0 if this DB instance is closed.
handle, or 0 if this DB instance is closed. Note that only
handles prepared via this.prepare() are counted, and not
handles prepared using capi.sqlite3_prepare_v3() (or
equivalent).
*/
openStatementCount: function(){
return this.pointer ? Object.keys(__stmtMap.get(this)).length : 0;

View File

@ -1358,6 +1358,16 @@ self.sqlite3InitModule = sqlite3InitModule;
if(wasm.bigIntEnabled){
T.assert(4n===db.changes(false,true));
}
let vals = db.selectValues('select a from t order by a limit 2');
T.assert( 2 === vals.length )
.assert( 1===vals[0] && 3===vals[1] );
vals = db.selectValues('select a from t order by a limit ?',
2, capi.SQLITE_TEXT);
T.assert( 2 === vals.length )
.assert( '1'===vals[0] && '3'===vals[1] );
vals = undefined;
let blob = db.selectValue("select b from t where a='blob'");
T.assert(blob instanceof Uint8Array).
assert(0x68===blob[0] && 0x69===blob[1]);
@ -2639,6 +2649,7 @@ self.sqlite3InitModule = sqlite3InitModule;
}/*OPFS util sanity checks*/)
;/* end OPFS tests */
////////////////////////////////////////////////////////////////////////
T.g('Session API')
.t({
name: 'Session API sanity checks',
@ -2664,15 +2675,10 @@ self.sqlite3InitModule = sqlite3InitModule;
T.assert(0===rc);
let pSession = wasm.peekPtr(ppOut);
T.assert(pSession && wasm.isPtr(pSession));
if(1){
capi.sqlite3session_table_filter(pSession, (pCtx, tbl)=>{
T.assert('t' === tbl).assert( 99 === pCtx );
return 1;
}, 99);
}else{
rc = capi.sqlite3session_attach(pSession, "t");
T.assert( 0 === rc );
}
db1.exec([
"update t set b='bTwo' where rowid=2;",
"update t set a='aThree' where rowid=3;",
@ -2681,8 +2687,27 @@ self.sqlite3InitModule = sqlite3InitModule;
]);
T.assert('bTwo' === db1.selectValue("select b from t where rowid=2"))
.assert(undefined === db1.selectValue('select a from t where rowid=1'))
.assert('b4' === db1.selectValue('select b from t where rowid=4'));
.assert('b4' === db1.selectValue('select b from t where rowid=4'))
.assert(3 === db1.selectValue('select count(*) from t'));
const testSessionEnable = false;
if(testSessionEnable){
rc = capi.sqlite3session_enable(pSession, 0);
T.assert( 0 === rc )
.assert( 0 === capi.sqlite3session_enable(pSession, -1) );
db1.exec("delete from t where rowid=2;");
rc = capi.sqlite3session_enable(pSession, 1);
T.assert( rc > 0 )
.assert( capi.sqlite3session_enable(pSession, -1) > 0 )
.assert(undefined === db1.selectValue('select a from t where rowid=2'));
}else{
warn("sqlite3session_enable() tests disabled due to unexpected results.",
"(Possibly a tester misunderstanding, as opposed to a bug.)");
}
let db1Count = db1.selectValue("select count(*) from t");
T.assert( db1Count === (testSessionEnable ? 2 : 3) );
/* Capture changeset and destroy session. */
let pnChanges = wasm.pstack.alloc('i32'),
ppChanges = wasm.pstack.allocPtr();
rc = capi.sqlite3session_changeset(pSession, pnChanges, ppChanges);
@ -2691,9 +2716,29 @@ self.sqlite3InitModule = sqlite3InitModule;
pSession = 0;
const pChanges = wasm.peekPtr(ppChanges),
nChanges = wasm.peek32(pnChanges);
T.assert( pChanges && wasm.isPtr( pChanges ) ).assert( nChanges > 0 );
T.assert( pChanges && wasm.isPtr( pChanges ) )
.assert( nChanges > 0 );
/* Revert db1 via an inverted changeset, but keep pChanges
and nChanges for application to db2. */
rc = capi.sqlite3changeset_invert( nChanges, pChanges, pnChanges, ppChanges );
T.assert( 0 === rc );
rc = capi.sqlite3changeset_apply(
db1, wasm.peek32(pnChanges), wasm.peekPtr(ppChanges), 0, (pCtx, eConflict, pIter)=>{
return 1;
}, 0
);
T.assert( 0 === rc );
wasm.dealloc( wasm.peekPtr(ppChanges) );
pnChanges = ppChanges = 0;
//log("pnChanges =", pnChanges, wasm.peek32(pnChanges), '@', pChanges);
T.assert('b2' === db1.selectValue("select b from t where rowid=2"))
.assert('a1' === db1.selectValue('select a from t where rowid=1'))
.assert(undefined === db1.selectValue('select b from t where rowid=4'));
db1Count = db1.selectValue("select count(*) from t");
T.assert(3 === db1Count);
/* Apply pre-reverted changeset (pChanges, nChanges) to
db2... */
rc = capi.sqlite3changeset_apply(
db2, nChanges, pChanges, 0, (pCtx, eConflict, pIter)=>{
return pCtx ? 1 : 0
@ -2701,15 +2746,25 @@ self.sqlite3InitModule = sqlite3InitModule;
);
wasm.dealloc( pChanges );
T.assert( 0 === rc )
.assert( 3 === db2.selectValue('select count(*) from t'))
.assert( 'b4' === db2.selectValue('select b from t where rowid=4') );
.assert( 'b4' === db2.selectValue('select b from t where rowid=4') )
.assert( 'aThree' === db2.selectValue('select a from t where rowid=3') )
.assert( undefined === db2.selectValue('select b from t where rowid=1') );
if(testSessionEnable){
T.assert( (undefined === db2.selectValue('select b from t where rowid=2')),
"But... the session was disabled when rowid=2 was deleted?" );
log("rowids from db2.t:",db2.selectValues('select rowid from t order by rowid'));
T.assert( 3 === db2.selectValue('select count(*) from t') );
}else{
T.assert( 'bTwo' === db2.selectValue('select b from t where rowid=2') )
.assert( 3 === db2.selectValue('select count(*) from t') );
}
}finally{
wasm.pstack.restore(stackPtr);
db1.close();
db2.close();
}
}
})
})/*session API sanity tests*/
;/*end of session API group*/;
////////////////////////////////////////////////////////////////////////

View File

@ -1,5 +1,5 @@
C Merge\swasm-session-api\sbranch\sinto\strunk,\sadding\sthe\ssession\sAPI\sto\sthe\sJS/WASM\scomponents.
D 2022-12-25T20:25:44.871
C Add\ssqlite3.oo1.DB.selectValues().\sCorrect\sa\slogic\serror\swhich\scould\scause\sDB.selectValue(),\sDB.selectArray(),\sand\sDB.selectObject()\sto\sfail\sto\sfinalize\sa\sstatement\sif\sa\scall\sto\sbind()\sfailed.\sAdd\smore\ssession\sAPI\stests.
D 2022-12-25T22:44:13.588
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -504,7 +504,7 @@ F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b
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-glue.js 594741f7cbff68f0b4a0c1a066bce335146de1124366377292e27d30f9a5f751
F ext/wasm/api/sqlite3-api-oo1.js ae4f6950913b4703b767f640a533675b45e9e6c462bf01e357cec16bc68943e2
F ext/wasm/api/sqlite3-api-oo1.js 8fdb63b6a88399e30dee6f80a38923f4ddab84b51002b23c4554bfbcde6ca558
F ext/wasm/api/sqlite3-api-prologue.js 9dfbb41ebc0aadfac9c41ae8d050187af39819fff4e4f22ac6a8a4f3008f722b
F ext/wasm/api/sqlite3-api-worker1.js e94ba98e44afccfa482874cd9acb325883ade50ed1f9f9526beb9de1711f182f
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
@ -555,7 +555,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b
F ext/wasm/tester1-worker.html d43f3c131d88f10d00aff3e328fed13c858d674ea2ff1ff90225506137f85aa9
F ext/wasm/tester1.c-pp.html d34bef3d48e5cbc1c7c06882ad240fec49bf88f5f65696cc2c72c416933aa406
F ext/wasm/tester1.c-pp.js 314e7bdbc73f558cf12c050c5af42f866195ee17bf451d63f7337052fcf44c7a
F ext/wasm/tester1.c-pp.js be6c06b3f1e244cd71c86aa075e532b15737e59c707ab03856a973999747cf46
F ext/wasm/tests/opfs/concurrency/index.html 86d8ac435074d1e7007b91105f4897f368c165e8cecb6a9aa3d81f5cf5dcbe70
F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
@ -2067,9 +2067,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 926d0c61a391c601adc2804d3fdaa8b667ae2abd565939cddfa12d5151b098f8 64e032602cf420851c8029603c76f5512000d1c9a40fa7a545528d69d6d1d4cc
R 5a9d5d7e14f03170b616d0bb48ba8894
T +closed 64e032602cf420851c8029603c76f5512000d1c9a40fa7a545528d69d6d1d4cc Closed\sby\sintegrate-merge.
P dfb8b651fa4faef2d3307a05512cdc479398484c3a59715827179c363861a777
R 11f4e29f6d9cd2a2b70132c232c1be63
U stephan
Z 42f975ba9994385873d5d768be40b720
Z 8afaa92daa5954ca91195b5a042039e6
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
dfb8b651fa4faef2d3307a05512cdc479398484c3a59715827179c363861a777
6adc8a10146190037d55d3328d2f78aa5233559f88d4aa70fbbf9e10145b9b6c