1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-12 13:01:09 +03:00

Merge trunk fixes.

FossilOrigin-Name: ccad277927baa2c36d0b5a03832dc51d9a7f3071587f0da0f2c1b44885c82e8d
This commit is contained in:
drh
2018-08-18 18:14:02 +00:00
15 changed files with 428 additions and 50 deletions

View File

@@ -1,5 +1,5 @@
C Have\sALTER\sTABLE\sRENAME\sCOLUMN\salso\sedit\strigger\sand\sview\sdefinitions.
D 2018-08-18T18:01:58.244
C Merge\strunk\sfixes.
D 2018-08-18T18:14:02.676
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
@@ -450,7 +450,7 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3
F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
F src/delete.c 107e28d3ef8bd72fd11953374ca9107cd74e8b09c3ded076a6048742d26ce7d2
F src/expr.c 4c1e40cdb1717b42e848835caf3e2b881f748cdcfabe3498e83634d1d2db5e26
F src/expr.c f44978812baf70d6abd5c727e354dc32d031ab981d36c3d58aec228ed68d84c6
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c f59253c0be4b1e9dfcb073b6d6d6ab83090ae50c08b5c113b76013c4b157cd6a
F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f
@@ -462,7 +462,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c c723716f0de7aa0a679300f7d3541c89645f4a9882161cecdb3093fc07f8cc4b
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
F src/loadext.c 6aae5739198d96c51ae6eb97c4a5b1744c22ed7a5a565a5399a717780d48a36b
F src/main.c df233667bbb6f05a8492ea93e0995abbeb816eab53e51e638a0dece1de0e83a3
F src/main.c 187011ff7a091ff4b8bea9481a42789c0fa094715b4e5d89352fb63377673490
F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@@ -482,11 +482,11 @@ F src/os.c 8aeb0b0f40f8f5b0da03fe49706695adaf42d2f516ab95abc72e86c245e119de
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c e681b2a3ab1085be3eb2e81254449782ca0bd0c38b73c48cb0c2480b8f2f25b9
F src/os_unix.c d6ee0c3b3f221dd5f3cec95f0400a581c516d04ea16a2916bba17c55127d8e06
F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 76d29b8a960dcb8b67210f095899d91e4a90673a6674ea58cfd1115b705a7fb9
F src/pager.h c571b064df842ec8f2e90855dead9acf4cbe0d1b2c05afe0ef0d0145f7fd0388
F src/pager.c 705de01dff9c3df9739c37a6d3b58cd2b1734fdabcef829b16cdc7721a9eeaa4
F src/pager.h ecc554a55bc55d1c4ba5e17137b72e238e00bd81e72ff2662d8b9c8c10ae3963
F src/parse.y 57f533353a4945370a60f66aa7be284c8a627509baa02d707982f906e4851f7d
F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
@@ -500,7 +500,7 @@ F src/resolve.c c58793195eaf2989b8d0688355cca15024cc792da155dffc44b85afae426c2d5
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c ae7396a314cc1bb1d767947cd57094e3a9ffcbb155ebc1b1c391e028c44a9a04
F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f
F src/sqlite.h.in c6451bb876adced3aba5b1682c6317d215c5eceaba21a6ce979e71a0b8d0bf95
F src/sqlite.h.in 82b5768e36ce796ecf93c73bd88bad99def831ce7d470138e213ac693bf4ceab
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
F src/sqliteInt.h 78e9b483adbdf928923a175f2c8470da89024b973b4b790486b6e8736b4c876f
@@ -508,7 +508,7 @@ F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
F src/tclsqlite.c e0bf71a6d24b8c23393c000abffab05979bbca2a72d0b0f79260e2cf1527fda5
F src/test1.c 55424c026dd93c06ad84ff4e46cec64aa3e12e767d50c31886e6a69ee53fe81e
F src/test1.c 31c491ccb536bd9916a084e732ffe783b3c8973f2586d5a56aed0e3a9701dfff
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
@@ -575,13 +575,13 @@ F src/vdbeInt.h 8ea493d994c6697cf7bccc60583a80a0222560490410f60f1113e90d36643ce0
F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611
F src/vdbeaux.c f03d4a1961ec282abaec5dbf7e5576ddb1eb01e6157335a232d8d9e57fd5eca1
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
F src/vdbemem.c 720df42ad8e5c7cb883573de40a185afef4a214903098a16f2bb14b62b2399b7
F src/vdbemem.c 0dc99941388a867a4dc77a8bed5dfc6024ee9c3ef147a09de844a6629086ec0c
F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
F src/vtab.c 8665561f244c137a2d17b5c3e5910d7303054fe841c5d510e53f23beb0089594
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c c617d78715e85d81fe5719b276d32186a37eb47a49d07a3d55ddbc541de043c9
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
F src/wal.c e4bcbd90072e9626126d6f3b8411159a0b984c1b9628d15237776578d5eda12d
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4
F src/where.c 155809967fbab889374dedf970ea6561b8fb519fcb165d6ba00776552ecc5cde
F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
@@ -803,7 +803,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
F test/enc3.test 6807f7a7740a00361ca8d0ccd66bc60c8dc5f2b6
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
F test/eqp.test 4fd69d25f21d8679f5fce13e639975879d89abf6acce4bd9cede133b7482aba7
F test/eqp.test fc00ad1a7f5b90bf1bbccbf877ae9abef8bf5c7896174830d438c8f91a6ead88
F test/errmsg.test eae9f091eb39ce7e20305de45d8e5d115b68fa856fba4ea6757b6ca3705ff7f9
F test/eval.test a64c9105d6ff163df7cf09d6ac29cdad5922078c
F test/exclusive.test 1206b87e192497d78c7f35552e86a9d05421498da300fb1cce5ca5351ccde3c3
@@ -1271,10 +1271,11 @@ F test/skipscan2.test ef143c6e4a5ba4f19c1d1e3f517811f7942bdf2142736cc568feb34e0b
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
F test/skipscan6.test 0b4cd1b4ac9f84d91454df513c99a4932fa07e8f27b8049bea605068b3e34ac7
F test/snapshot.test 85735bd997a4f6d710140c28fd860519a299649f
F test/snapshot.test fef12fc5c16ff21c4748509401cfba7d9a3d91156f1bfe23fb881d3bfc65ddfe
F test/snapshot2.test 925e42427e923262db63c9d7155183f889e3e99feaedec4075f659e51608344f
F test/snapshot3.test 9719443594a04778861bd20d12596c5f880af177d6cd62f111da3198cafc6096
F test/snapshot_fault.test 52c5e97ebd218846a8ae2da4d147d3e77d71f963
F test/snapshot_up.test b778a04561a67b8bfde828f473a8d31dbde23e3f648e36237e0369421e08f23c
F test/soak.test 18944cf21b94a7fe0df02016a6ee1e9632bc4e8d095a0cb49d95e15d5cca2d5c
F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087
F test/sort.test c2adc635c2564241fefec0b3a68391ef6868fd3b
@@ -1756,8 +1757,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P ad15486022209205c65fb5ffdbe30a7b99379170451e6aff4bab6e90b549d6c7 7fa1faeaff30b74b68ee6f4b363d837f21cf313d8262361c901bda884df139a2
R 4b2d31defa56ef33764a237b1d928d0d
T +closed 7fa1faeaff30b74b68ee6f4b363d837f21cf313d8262361c901bda884df139a2
U dan
Z 4f1d814f6f719b632fdfddd911dbafb8
P 7908e8a4a3b9577211a5d3da9c4142c46e9d5872be4a6499ec053f2b547019b8 6f5e84bafcaf425cb664c7db8179c9c09a13c96aaf057551c04a919ca554d057
R bf540842727f950c03e1bbd37a331e62
U drh
Z 4ca7886da2a9947381aad1deb46a422b

View File

@@ -1 +1 @@
7908e8a4a3b9577211a5d3da9c4142c46e9d5872be4a6499ec053f2b547019b8
ccad277927baa2c36d0b5a03832dc51d9a7f3071587f0da0f2c1b44885c82e8d

View File

@@ -2369,7 +2369,8 @@ int sqlite3FindInIndex(
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
eType = IN_INDEX_ROWID;
ExplainQueryPlan((pParse, 0,
"USING ROWID SEARCH ON TABLE %s FOR IN-OPERATOR",pTab->zName));
sqlite3VdbeJumpHere(v, iAddr);
}else{
Index *pIdx; /* Iterator variable */

View File

@@ -4209,11 +4209,29 @@ int sqlite3_snapshot_open(
iDb = sqlite3FindDbName(db, zDb);
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
rc = sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), pSnapshot);
if( sqlite3BtreeIsInTrans(pBt)==0 ){
Pager *pPager = sqlite3BtreePager(pBt);
int bUnlock = 0;
if( sqlite3BtreeIsInReadTrans(pBt) ){
if( db->nVdbeActive==0 ){
rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot);
if( rc==SQLITE_OK ){
bUnlock = 1;
rc = sqlite3BtreeCommit(pBt);
}
}
}else{
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
rc = sqlite3PagerSnapshotOpen(pPager, pSnapshot);
}
if( rc==SQLITE_OK ){
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0);
sqlite3PagerSnapshotOpen(pPager, 0);
}
if( bUnlock ){
sqlite3PagerSnapshotUnlock(pPager);
}
}
}

View File

@@ -2111,7 +2111,7 @@ static int unixClose(sqlite3_file *id){
*/
assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );
sqlite3_mutex_enter(pInode->pLockMutex);
if( pFile->pInode->nLock ){
if( pInode->nLock ){
/* If there are outstanding locks, do not actually close the file just
** yet because that would clear those locks. Instead, add the file
** descriptor to pInode->pUnused list. It will be automatically closed

View File

@@ -7653,6 +7653,38 @@ int sqlite3PagerSnapshotRecover(Pager *pPager){
}
return rc;
}
/*
** The caller currently has a read transaction open on the database.
** If this is not a WAL database, SQLITE_ERROR is returned. Otherwise,
** this function takes a SHARED lock on the CHECKPOINTER slot and then
** checks if the snapshot passed as the second argument is still
** available. If so, SQLITE_OK is returned.
**
** If the snapshot is not available, SQLITE_ERROR is returned. Or, if
** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error
** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER
** lock is released before returning.
*/
int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot){
int rc;
if( pPager->pWal ){
rc = sqlite3WalSnapshotCheck(pPager->pWal, pSnapshot);
}else{
rc = SQLITE_ERROR;
}
return rc;
}
/*
** Release a lock obtained by an earlier successful call to
** sqlite3PagerSnapshotCheck().
*/
void sqlite3PagerSnapshotUnlock(Pager *pPager){
assert( pPager->pWal );
return sqlite3WalSnapshotUnlock(pPager->pWal);
}
#endif /* SQLITE_ENABLE_SNAPSHOT */
#endif /* !SQLITE_OMIT_WAL */

View File

@@ -186,6 +186,8 @@ int sqlite3PagerSharedLock(Pager *pPager);
int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
int sqlite3PagerSnapshotRecover(Pager *pPager);
int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
void sqlite3PagerSnapshotUnlock(Pager *pPager);
# endif
#else
# define sqlite3PagerUseWal(x,y) 0

View File

@@ -9035,22 +9035,33 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
** CAPI3REF: Start a read transaction on an historical snapshot
** METHOD: sqlite3_snapshot
**
** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
** read transaction for schema S of
** [database connection] D such that the read transaction
** refers to historical [snapshot] P, rather than the most
** recent change to the database.
** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
** or an appropriate [error code] if it fails.
** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read
** transaction or upgrades an existing one for schema S of
** [database connection] D such that the read transaction refers to
** historical [snapshot] P, rather than the most recent change to the
** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK
** on success or an appropriate [error code] if it fails.
**
** ^In order to succeed, the database connection must not be in
** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there
** is already a read transaction open on schema S, then the database handle
** must have no active statements (SELECT statements that have been passed
** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()).
** SQLITE_ERROR is returned if either of these conditions is violated, or
** if schema S does not exist, or if the snapshot object is invalid.
**
** ^A call to sqlite3_snapshot_open() will fail to open if the specified
** snapshot has been overwritten by a [checkpoint]. In this case
** SQLITE_BUSY_SNAPSHOT is returned.
**
** If there is already a read transaction open when this function is
** invoked, then the same read transaction remains open (on the same
** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_BUSY_SNAPSHOT
** is returned. If another error code - for example SQLITE_PROTOCOL or an
** SQLITE_IOERR error code - is returned, then the final state of the
** read transaction is undefined. If SQLITE_OK is returned, then the
** read transaction is now open on database snapshot P.
**
** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
** the first operation following the [BEGIN] that takes the schema S
** out of [autocommit mode].
** ^In other words, schema S must not currently be in
** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
** database connection D must be out of [autocommit mode].
** ^A [snapshot] will fail to open if it has been overwritten by a
** [checkpoint].
** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
** database connection D does not know that the database file for
** schema S is in [WAL mode]. A database connection might not know

View File

@@ -2393,6 +2393,8 @@ static int SQLITE_TCLAPI test_snapshot_open(
if( rc!=SQLITE_OK ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
return TCL_ERROR;
}else{
Tcl_ResetResult(interp);
}
return TCL_OK;
}

View File

@@ -1782,11 +1782,11 @@ int sqlite3Stat4Column(
int iCol, /* Column to extract */
sqlite3_value **ppVal /* OUT: Extracted value */
){
u32 t; /* a column type code */
u32 t = 0; /* a column type code */
int nHdr; /* Size of the header in the record */
int iHdr; /* Next unread header byte */
int iField; /* Next unread data byte */
int szField; /* Size of the current data field */
int szField = 0; /* Size of the current data field */
int i; /* Column index */
u8 *a = (u8*)pRec; /* Typecast byte array */
Mem *pMem = *ppVal; /* Write result into this Mem object */

View File

@@ -3769,6 +3769,43 @@ int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1;
return 0;
}
/*
** The caller currently has a read transaction open on the database.
** This function takes a SHARED lock on the CHECKPOINTER slot and then
** checks if the snapshot passed as the second argument is still
** available. If so, SQLITE_OK is returned.
**
** If the snapshot is not available, SQLITE_ERROR is returned. Or, if
** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error
** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER
** lock is released before returning.
*/
int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){
int rc;
rc = walLockShared(pWal, WAL_CKPT_LOCK);
if( rc==SQLITE_OK ){
WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
|| pNew->mxFrame<walCkptInfo(pWal)->nBackfillAttempted
){
rc = SQLITE_BUSY_SNAPSHOT;
walUnlockShared(pWal, WAL_CKPT_LOCK);
}
}
return rc;
}
/*
** Release a lock obtained by an earlier successful call to
** sqlite3WalSnapshotCheck().
*/
void sqlite3WalSnapshotUnlock(Wal *pWal){
assert( pWal );
walUnlockShared(pWal, WAL_CKPT_LOCK);
}
#endif /* SQLITE_ENABLE_SNAPSHOT */
#ifdef SQLITE_ENABLE_ZIPVFS

View File

@@ -132,6 +132,8 @@ int sqlite3WalHeapMemory(Wal *pWal);
int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
int sqlite3WalSnapshotRecover(Wal *pWal);
int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot);
void sqlite3WalSnapshotUnlock(Wal *pWal);
#endif
#ifdef SQLITE_ENABLE_ZIPVFS

View File

@@ -743,10 +743,84 @@ det 8.2.4 "SELECT count(*) FROM t1" {
`--SCAN TABLE t1
}
# 2018-08-16: While working on Fossil I discovered that EXPLAIN QUERY PLAN
# did not describe IN operators implemented using a ROWID lookup. These
# test cases ensure that problem as been fixed.
#
do_execsql_test 9.0 {
-- Schema from Fossil 2018-08-16
CREATE TABLE forumpost(
fpid INTEGER PRIMARY KEY,
froot INT,
fprev INT,
firt INT,
fmtime REAL
);
CREATE INDEX forumthread ON forumpost(froot,fmtime);
CREATE TABLE blob(
rid INTEGER PRIMARY KEY,
rcvid INTEGER,
size INTEGER,
uuid TEXT UNIQUE NOT NULL,
content BLOB,
CHECK( length(uuid)>=40 AND rid>0 )
);
CREATE TABLE event(
type TEXT,
mtime DATETIME,
objid INTEGER PRIMARY KEY,
tagid INTEGER,
uid INTEGER REFERENCES user,
bgcolor TEXT,
euser TEXT,
user TEXT,
ecomment TEXT,
comment TEXT,
brief TEXT,
omtime DATETIME
);
CREATE INDEX event_i1 ON event(mtime);
CREATE TABLE private(rid INTEGER PRIMARY KEY);
}
do_eqp_test 9.1 {
WITH thread(age,duration,cnt,root,last) AS (
SELECT
julianday('now') - max(fmtime) AS age,
max(fmtime) - min(fmtime) AS duration,
sum(fprev IS NULL) AS msg_count,
froot,
(SELECT fpid FROM forumpost
WHERE froot=x.froot
AND fpid NOT IN private
ORDER BY fmtime DESC LIMIT 1)
FROM forumpost AS x
WHERE fpid NOT IN private --- Ensure this table mentioned in EQP output!
GROUP BY froot
ORDER BY 1 LIMIT 26 OFFSET 5
)
SELECT
thread.age,
thread.duration,
thread.cnt,
blob.uuid,
substr(event.comment,instr(event.comment,':')+1)
FROM thread, blob, event
WHERE blob.rid=thread.last
AND event.objid=thread.last
ORDER BY 1;
} {
QUERY PLAN
|--MATERIALIZE xxxxxx
| |--SCAN TABLE forumpost AS x USING INDEX forumthread
| |--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR
| |--CORRELATED SCALAR SUBQUERY
| | |--SEARCH TABLE forumpost USING COVERING INDEX forumthread (froot=?)
| | `--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR
| `--USE TEMP B-TREE FOR ORDER BY
|--SCAN SUBQUERY xxxxxx
|--SEARCH TABLE blob USING INTEGER PRIMARY KEY (rowid=?)
|--SEARCH TABLE event USING INTEGER PRIMARY KEY (rowid=?)
`--USE TEMP B-TREE FOR ORDER BY
}
finish_test

View File

@@ -217,9 +217,19 @@ foreach {tn tcl} {
SELECT * FROM t2;
}
} {a b c d e f}
do_test $tn.3.2.2 {
list [catch {snapshot_open db main $snapshot } msg] $msg
# Update - it is no longer an error to have a read-transaction open,
# provided there are no active SELECT statements.
do_test $tn.3.2.2a {
db eval "SELECT * FROM t2" {
set res [list [catch {snapshot_open db main $snapshot } msg] $msg]
break
}
set res
} {1 SQLITE_ERROR}
do_test $tn.3.2.2b {
snapshot_open db main $snapshot
} {}
do_test $tn.3.2.3 {
execsql {
@@ -231,12 +241,17 @@ foreach {tn tcl} {
} {1 SQLITE_ERROR}
do_execsql_test $tn.3.2.4 COMMIT
do_test $tn.3.3.1 {
do_test $tn.3.3.1a {
execsql { PRAGMA journal_mode = DELETE }
execsql { BEGIN }
list [catch {snapshot_open db main $snapshot } msg] $msg
} {1 SQLITE_ERROR}
do_test $tn.3.3.1b {
execsql { COMMIT ; BEGIN ; SELECT * FROM t2 }
list [catch {snapshot_open db main $snapshot } msg] $msg
} {1 SQLITE_ERROR}
do_test $tn.$tn.3.3.2 {
snapshot_free $snapshot
execsql COMMIT

184
test/snapshot_up.test Normal file
View File

@@ -0,0 +1,184 @@
# 2018 August 6
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Tests for calling sqlite3_snapshot_open() when there is already
# a read transaction open on the database.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !snapshot {finish_test; return}
set testprefix snapshot_up
# This test does not work with the inmemory_journal permutation. The reason
# is that each connection opened as part of this permutation executes
# "PRAGMA journal_mode=memory", which fails if the database is in wal mode
# and there are one or more existing connections.
if {[permutation]=="inmemory_journal"} {
finish_test
return
}
do_execsql_test 1.0 {
CREATE TABLE t1(a, b, c);
PRAGMA journal_mode = wal;
INSERT INTO t1 VALUES(1, 2, 3);
INSERT INTO t1 VALUES(4, 5, 6);
INSERT INTO t1 VALUES(7, 8, 9);
} {wal}
do_test 1.1 {
execsql BEGIN
set ::snap1 [sqlite3_snapshot_get db main]
execsql COMMIT
execsql { INSERT INTO t1 VALUES(10, 11, 12); }
execsql BEGIN
set ::snap2 [sqlite3_snapshot_get db main]
execsql COMMIT
execsql { INSERT INTO t1 VALUES(13, 14, 15); }
execsql BEGIN
set ::snap3 [sqlite3_snapshot_get db main]
execsql COMMIT
} {}
do_execsql_test 1.2 {
BEGIN;
SELECT * FROM t1
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15}
do_test 1.3 {
sqlite3_snapshot_open db main $::snap1
execsql { SELECT * FROM t1 }
} {1 2 3 4 5 6 7 8 9}
do_test 1.4 {
sqlite3_snapshot_open db main $::snap2
execsql { SELECT * FROM t1 }
} {1 2 3 4 5 6 7 8 9 10 11 12}
do_test 1.5 {
sqlite3 db2 test.db
execsql { PRAGMA wal_checkpoint } db2
} {0 5 4}
do_execsql_test 1.6 {
SELECT * FROM t1
} {1 2 3 4 5 6 7 8 9 10 11 12}
do_test 1.7 {
list [catch { sqlite3_snapshot_open db main $::snap1 } msg] $msg
} {1 SQLITE_BUSY_SNAPSHOT}
do_execsql_test 1.8 {
SELECT * FROM t1
} {1 2 3 4 5 6 7 8 9 10 11 12}
do_test 1.9 {
execsql { COMMIT ; BEGIN }
list [catch { sqlite3_snapshot_open db main $::snap1 } msg] $msg
} {1 SQLITE_BUSY_SNAPSHOT}
do_test 1.10 {
execsql { COMMIT }
execsql {
PRAGMA wal_checkpoint;
DELETE FROM t1 WHERE a = 1;
} db2
execsql BEGIN
set ::snap4 [sqlite3_snapshot_get db main]
execsql COMMIT
execsql {
DELETE FROM t1 WHERE a = 4;
} db2
} {}
do_test 1.11 {
execsql {
BEGIN;
SELECT * FROM t1
}
} {7 8 9 10 11 12 13 14 15}
do_test 1.12 {
sqlite3_snapshot_open db main $::snap4
execsql { SELECT * FROM t1 }
} {4 5 6 7 8 9 10 11 12 13 14 15}
do_test 1.13 {
list [catch { sqlite3_snapshot_open db main $::snap3 } msg] $msg
} {1 SQLITE_BUSY_SNAPSHOT}
do_test 1.14 {
execsql { SELECT * FROM t1 }
} {4 5 6 7 8 9 10 11 12 13 14 15}
db close
db2 close
sqlite3 db test.db
do_execsql_test 1.15 {
BEGIN;
SELECT * FROM t1
} {7 8 9 10 11 12 13 14 15}
do_test 1.16 {
list [catch { sqlite3_snapshot_open db main $::snap4 } msg] $msg
} {1 SQLITE_BUSY_SNAPSHOT}
do_execsql_test 1.17 { COMMIT }
sqlite3_snapshot_free $::snap1
sqlite3_snapshot_free $::snap2
sqlite3_snapshot_free $::snap3
sqlite3_snapshot_free $::snap4
#-------------------------------------------------------------------------
catch { db close }
sqlite3 db test.db
sqlite3 db2 test.db
sqlite3 db3 test.db
proc xBusy {args} { return 1 }
db3 busy xBusy
do_test 2.1 {
execsql { INSERT INTO t1 VALUES(16, 17, 18) } db2
execsql BEGIN
set ::snap1 [sqlite3_snapshot_get db main]
execsql COMMIT
execsql { INSERT INTO t1 VALUES(19, 20, 21) } db2
execsql BEGIN
set ::snap2 [sqlite3_snapshot_get db main]
execsql COMMIT
set {} {}
} {}
do_execsql_test -db db2 2.2 {
BEGIN;
INSERT INTO t1 VALUES(19, 20, 21);
}
do_test 2.3 {
execsql BEGIN
sqlite3_snapshot_open db main $::snap1
execsql { SELECT * FROM t1 }
} {7 8 9 10 11 12 13 14 15 16 17 18}
proc xBusy {args} {
set ::res [list [catch { sqlite3_snapshot_open db main $::snap2 } msg] $msg]
return 1
}
db3 busy xBusy
do_test 2.4 {
execsql {PRAGMA wal_checkpoint = restart} db3
set ::res
} {1 SQLITE_BUSY}
sqlite3_snapshot_free $::snap1
sqlite3_snapshot_free $::snap2
finish_test