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:
@ -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.
|
selectObject() methods.
|
||||||
*/
|
*/
|
||||||
const __selectFirstRow = (db, sql, bind, getArg)=>{
|
const __selectFirstRow = (db, sql, bind, ...getArgs)=>{
|
||||||
let stmt, rc;
|
const stmt = db.prepare(sql);
|
||||||
try {
|
try {
|
||||||
stmt = db.prepare(sql).bind(bind);
|
return stmt.bind(bind).step() ? stmt.get(...getArgs) : undefined;
|
||||||
if(stmt.step()) rc = stmt.get(getArg);
|
|
||||||
}finally{
|
}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.
|
selectObjects() methods.
|
||||||
*/
|
*/
|
||||||
const __selectAll =
|
const __selectAll =
|
||||||
@ -1083,15 +1081,31 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
Throws on error (e.g. malformed SQL).
|
Throws on error (e.g. malformed SQL).
|
||||||
*/
|
*/
|
||||||
selectValue: function(sql,bind,asType){
|
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 {
|
try {
|
||||||
stmt = this.prepare(sql).bind(bind);
|
stmt.bind(bind);
|
||||||
if(stmt.step()) rc = stmt.get(0,asType);
|
while(stmt.step()) rc.push(stmt.get(0,asType));
|
||||||
}finally{
|
}finally{
|
||||||
if(stmt) stmt.finalize();
|
stmt.finalize();
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Prepares the given SQL, step()s it one time, and returns an
|
Prepares the given SQL, step()s it one time, and returns an
|
||||||
array containing the values of the first result row. If it has
|
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
|
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(){
|
openStatementCount: function(){
|
||||||
return this.pointer ? Object.keys(__stmtMap.get(this)).length : 0;
|
return this.pointer ? Object.keys(__stmtMap.get(this)).length : 0;
|
||||||
@ -1611,7 +1628,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
Fetches the value from the given 0-based column index of
|
Fetches the value from the given 0-based column index of
|
||||||
the current data row, throwing if index is out of range.
|
the current data row, throwing if index is out of range.
|
||||||
|
|
||||||
Requires that step() has just returned a truthy value, else
|
Requires that step() has just returned a truthy value, else
|
||||||
an exception is thrown.
|
an exception is thrown.
|
||||||
|
@ -1358,6 +1358,16 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
if(wasm.bigIntEnabled){
|
if(wasm.bigIntEnabled){
|
||||||
T.assert(4n===db.changes(false,true));
|
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'");
|
let blob = db.selectValue("select b from t where a='blob'");
|
||||||
T.assert(blob instanceof Uint8Array).
|
T.assert(blob instanceof Uint8Array).
|
||||||
assert(0x68===blob[0] && 0x69===blob[1]);
|
assert(0x68===blob[0] && 0x69===blob[1]);
|
||||||
@ -2639,6 +2649,7 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
}/*OPFS util sanity checks*/)
|
}/*OPFS util sanity checks*/)
|
||||||
;/* end OPFS tests */
|
;/* end OPFS tests */
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
T.g('Session API')
|
T.g('Session API')
|
||||||
.t({
|
.t({
|
||||||
name: 'Session API sanity checks',
|
name: 'Session API sanity checks',
|
||||||
@ -2664,15 +2675,10 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
T.assert(0===rc);
|
T.assert(0===rc);
|
||||||
let pSession = wasm.peekPtr(ppOut);
|
let pSession = wasm.peekPtr(ppOut);
|
||||||
T.assert(pSession && wasm.isPtr(pSession));
|
T.assert(pSession && wasm.isPtr(pSession));
|
||||||
if(1){
|
capi.sqlite3session_table_filter(pSession, (pCtx, tbl)=>{
|
||||||
capi.sqlite3session_table_filter(pSession, (pCtx, tbl)=>{
|
T.assert('t' === tbl).assert( 99 === pCtx );
|
||||||
T.assert('t' === tbl).assert( 99 === pCtx );
|
return 1;
|
||||||
return 1;
|
}, 99);
|
||||||
}, 99);
|
|
||||||
}else{
|
|
||||||
rc = capi.sqlite3session_attach(pSession, "t");
|
|
||||||
T.assert( 0 === rc );
|
|
||||||
}
|
|
||||||
db1.exec([
|
db1.exec([
|
||||||
"update t set b='bTwo' where rowid=2;",
|
"update t set b='bTwo' where rowid=2;",
|
||||||
"update t set a='aThree' where rowid=3;",
|
"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"))
|
T.assert('bTwo' === db1.selectValue("select b from t where rowid=2"))
|
||||||
.assert(undefined === db1.selectValue('select a from t where rowid=1'))
|
.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'),
|
let pnChanges = wasm.pstack.alloc('i32'),
|
||||||
ppChanges = wasm.pstack.allocPtr();
|
ppChanges = wasm.pstack.allocPtr();
|
||||||
rc = capi.sqlite3session_changeset(pSession, pnChanges, ppChanges);
|
rc = capi.sqlite3session_changeset(pSession, pnChanges, ppChanges);
|
||||||
@ -2691,9 +2716,29 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
pSession = 0;
|
pSession = 0;
|
||||||
const pChanges = wasm.peekPtr(ppChanges),
|
const pChanges = wasm.peekPtr(ppChanges),
|
||||||
nChanges = wasm.peek32(pnChanges);
|
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;
|
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(
|
rc = capi.sqlite3changeset_apply(
|
||||||
db2, nChanges, pChanges, 0, (pCtx, eConflict, pIter)=>{
|
db2, nChanges, pChanges, 0, (pCtx, eConflict, pIter)=>{
|
||||||
return pCtx ? 1 : 0
|
return pCtx ? 1 : 0
|
||||||
@ -2701,15 +2746,25 @@ self.sqlite3InitModule = sqlite3InitModule;
|
|||||||
);
|
);
|
||||||
wasm.dealloc( pChanges );
|
wasm.dealloc( pChanges );
|
||||||
T.assert( 0 === rc )
|
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{
|
}finally{
|
||||||
wasm.pstack.restore(stackPtr);
|
wasm.pstack.restore(stackPtr);
|
||||||
db1.close();
|
db1.close();
|
||||||
db2.close();
|
db2.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})/*session API sanity tests*/
|
||||||
;/*end of session API group*/;
|
;/*end of session API group*/;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
15
manifest
15
manifest
@ -1,5 +1,5 @@
|
|||||||
C Merge\swasm-session-api\sbranch\sinto\strunk,\sadding\sthe\ssession\sAPI\sto\sthe\sJS/WASM\scomponents.
|
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-25T20:25:44.871
|
D 2022-12-25T22:44:13.588
|
||||||
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
|
||||||
@ -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/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 594741f7cbff68f0b4a0c1a066bce335146de1124366377292e27d30f9a5f751
|
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-prologue.js 9dfbb41ebc0aadfac9c41ae8d050187af39819fff4e4f22ac6a8a4f3008f722b
|
||||||
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
|
||||||
@ -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 314e7bdbc73f558cf12c050c5af42f866195ee17bf451d63f7337052fcf44c7a
|
F ext/wasm/tester1.c-pp.js be6c06b3f1e244cd71c86aa075e532b15737e59c707ab03856a973999747cf46
|
||||||
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,9 +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 926d0c61a391c601adc2804d3fdaa8b667ae2abd565939cddfa12d5151b098f8 64e032602cf420851c8029603c76f5512000d1c9a40fa7a545528d69d6d1d4cc
|
P dfb8b651fa4faef2d3307a05512cdc479398484c3a59715827179c363861a777
|
||||||
R 5a9d5d7e14f03170b616d0bb48ba8894
|
R 11f4e29f6d9cd2a2b70132c232c1be63
|
||||||
T +closed 64e032602cf420851c8029603c76f5512000d1c9a40fa7a545528d69d6d1d4cc Closed\sby\sintegrate-merge.
|
|
||||||
U stephan
|
U stephan
|
||||||
Z 42f975ba9994385873d5d768be40b720
|
Z 8afaa92daa5954ca91195b5a042039e6
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
dfb8b651fa4faef2d3307a05512cdc479398484c3a59715827179c363861a777
|
6adc8a10146190037d55d3328d2f78aa5233559f88d4aa70fbbf9e10145b9b6c
|
Reference in New Issue
Block a user