From: drh Date: Tue, 25 Aug 2020 19:09:07 +0000 (+0000) Subject: Add support for the sqlite3_txn_state() interface. X-Git-Tag: version-3.34.0~131 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=99744fa4ab7696f090e6fd8615b12e9b7e9792e6;p=thirdparty%2Fsqlite.git Add support for the sqlite3_txn_state() interface. FossilOrigin-Name: ad195e3dd89d0f33b50070c18fb8f43c4eb24162515dfdd7c04d9e7d96b902a2 --- diff --git a/manifest b/manifest index 4b8bd936e0..68c67e596b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Reduce\sthe\sN\sin\sthe\slogN\sterm\sfor\sthe\ssorting\scost\sassociated\swith\scomputing\nDISTINCT\sby\sB-Tree\sby\shalf,\sunder\sthe\sassumption\sthat\sthe\sDISTINCT\swill\neliminate\sabout\shalf\sthe\srows\sof\soutput.\s\sThis\sis\sreally\sa\swild\sguess.\s\sBut\nwe\sdo\snot\shave\sany\sbetter\sway\sof\sestimating\swhat\sthe\srow-count\sreduction\sdue\nto\sDISTINCT\swill\sactually\sbe. -D 2020-08-24T23:44:27.235 +C Add\ssupport\sfor\sthe\ssqlite3_txn_state()\sinterface. +D 2020-08-25T19:09:07.606 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -471,14 +471,14 @@ F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c 805de23ddca536181f8f0439df989fdd4a2f76c40bc305ec9fe2f211f68c89e8 F src/analyze.c 5cffff3d355858cd22bfc6e20ac7203510d2e1cc935086eb06f4abb2f579f628 -F src/attach.c 0b11e00c166b622c84ec176773b1d691c61ad07d247809e3e1635d4e99e71d30 +F src/attach.c 0f497c15c4cfe3bdcb214f0dbdbbb6c5ed7e8a9308ac445c7959f5e5780437a9 F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 -F src/backup.c b1c90cd4110248c8e1273ff4578d3a84c0c34725e1b96dacd4a6294a908702de +F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 1439fd9b45d4d1883c53752daef42af489adaa1a1508fa39dedbc9c80ea21a2f -F src/btree.h 7af72bbb4863c331c8f6753277ab40ee67d2a2125a63256d5c25489722ec162b -F src/btreeInt.h 83166f6daeb91062b6ae9ee6247b3ad07e40eba58f3c05ba9e8dedad4ab1ea38 +F src/btree.c 634381c86f363dfd470c9dbe64c07363e746cb9917573f67381c861b1d264d8d +F src/btree.h c299ab8b279230de1ef457f298ade9848c7339de6ef88a55beaf62bf0345eb15 +F src/btreeInt.h d1f713b2947a054c3532154a4d6b2bb8c4698fb54432f171966bdd06728ab1be F src/build.c a80bc79f0be20185e2005b74e9a23f8abb8fbb3cc54ed769a21865f79d507d90 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e @@ -499,7 +499,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 1103270dfc1a94d1ca69f36dc3e021a335459583195e4b9e5a4d6e3c840279ba F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 436af4968c6954d304fce9efa12719367bd8f37b19b93b71d6ad607e85adbb47 -F src/main.c 09580279145f27f3db206ef44dcb3a8875a42644230f79c7e54aff35e71668f0 +F src/main.c d71b989398a4cdb4e7ece0478b763834d7732fb78dd24702d36366743853ac82 F src/malloc.c 22d5bdd9fe88ae4fad1b91a1b9735104b82853ffef868f1f05517d60dc1875f5 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@ -528,16 +528,16 @@ F src/parse.y 5bdb760a29c0b25caf7e80e82210b81cd2ea3066d5199ca29e6eac40b34bc184 F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a -F src/pragma.c bdb600be936f66b9fe69d26dfbba4528beaaf4f95c479c85b328a92484e0bf71 +F src/pragma.c 5435b9fe17f7728bd460f52d6d9388e7e45658c6f5549f28fc2d408be9efd2d5 F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf -F src/prepare.c 3d5a761d026052bc888d1b803a06dd2bfe245e8e836d4689f927003549148b0f +F src/prepare.c 38ae9c2e3550bfa496886a862a5344c420ded052fd92294f409a07a53f372ffe F src/printf.c 9efcd4e984f22bcccb1ded37a1178cac98f6e3a0534e1e0629f64899971f8838 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 97b91fb25d86881ff20c9ad2ad98412c6c1bb5f7d6c9bb044db250cbc9cfcd4b F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 233e884d7da6601486c7b93aedb97fd29302ae5c03742d0e0eccb4790638bb77 F src/shell.c.in b6d5d6ebeb8903e4946f23f0886f24133e0a9b6ecbc4cf90ede422ba297e73d5 -F src/sqlite.h.in d2c03414a8ee5d4a6855c04dd7cd5998e45139b0fe66b65bae86d4223edd091f +F src/sqlite.h.in b91e4a5b9b25eb95260be0bf9716d2bdba0da06b72eb439f41592b226f58881d F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 2d1af80082edffd71c6f96f70ad1ce6a4fb46615ad10291fc77fe0dea9ff0197 F src/sqliteInt.h 7dd1f3a93e801c90cf108149d041c6cc32d3e9503d66aa415455dae1614b6b53 @@ -545,7 +545,7 @@ F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a3 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/tclsqlite.c 986b6391f02cd9b53c1d688be55899f6ffddeb8e8014cd83c1b73ff912579a71 -F src/test1.c 24b9cd0863ecc4d3920f4999c40e876c2bd92f3cc5879c48b99abe02c546ed18 +F src/test1.c 9e52fb797bf74fa327295df38881aa3ade0824bfb0c14abd0719e555b169fd55 F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5 F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644 F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159 @@ -606,12 +606,12 @@ F src/update.c 55a6203008d033fc1a9c125d7a0a61efdb79bbb2e6db427b917d1d427b4639be F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c8bf30c4356b091bcc3b624d0e24b2b4d11b8be4d6c90d8e0705971e15cc819b -F src/vacuum.c 1c4f8e2f39d950037f4cf946b6858c993d3a54c3101f78e05c76460a073afcf0 -F src/vdbe.c e9f7f818f128c8600058c0eabb6b3975974c95153a104d340f419adabbc15b9f +F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 +F src/vdbe.c e88c94a53f571b6cdc67a8dbdc2ac49ddb3c5b2435aad72d68612b2464728faa F src/vdbe.h 83603854bfa5851af601fc0947671eb260f4363e62e960e8a994fb9bbcd2aaa1 F src/vdbeInt.h 762abffb7709f19c2cb74af1bba73a900f762e64f80d69c31c9ae89ed1066b60 F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9 -F src/vdbeaux.c 73854da7a9a4f12db72a855758214173c82f46a14be6cb19e63677ba02c97cae +F src/vdbeaux.c b39d2e0e7126cd4629874dd7b67162b9f0d200b620d2b4c16d400949a2f1094b F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1 F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f F src/vdbesort.c 2be76d26998ce2b3324cdcc9f6443728e54b6c7677c553ad909c7d7cfab587df @@ -1588,7 +1588,7 @@ F test/tpch01.test 7c4eb8cdd79c568f46d344b3e789c9fdb8a766d112871352704861f3fca32 F test/trace.test a659a9862957f4789e37a92b3bf6d2caf5c86b02cdeefc41e850ae53acf6992a F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983 F test/trace3.test 1dff966888773ff1bfea01c080caf15417892b3f998408fe920c4791f7337144 -F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6 +F test/trans.test 45f6f9ab6f66a7b5744f1caac06b558f95da62501916906cf55586a896f9f439 F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76 F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94 F test/transitive1.test 293300f46916569f08875cdb2fe2134be2c27677 @@ -1879,7 +1879,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 493a25949b9a6d0be82169b597133e491d8be4f4147b6eae135b06c1d810abd3 -R ddd62187ac7223d5e6ce61819bf672f8 +P 8787417ec1da8071d84c6ff0d7a90b5fd458ab6baba871327f36bc4e1bceca61 +R 722b615829cb4461022a7ec168b6d94f U drh -Z 3f2dc6629d15095497f0f8f6b9a935ba +Z af427d9ac0f51142694fe72fc2db903f diff --git a/manifest.uuid b/manifest.uuid index 7544a576c2..59ffa50ff6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8787417ec1da8071d84c6ff0d7a90b5fd458ab6baba871327f36bc4e1bceca61 \ No newline at end of file +ad195e3dd89d0f33b50070c18fb8f43c4eb24162515dfdd7c04d9e7d96b902a2 \ No newline at end of file diff --git a/src/attach.c b/src/attach.c index 545159d3ea..3b5c57f0cc 100644 --- a/src/attach.c +++ b/src/attach.c @@ -293,7 +293,9 @@ static void detachFunc( sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName); goto detach_error; } - if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){ + if( sqlite3BtreeTxnState(pDb->pBt)!=SQLITE_TXN_NONE + || sqlite3BtreeIsInBackup(pDb->pBt) + ){ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); goto detach_error; } diff --git a/src/backup.c b/src/backup.c index 77e7ed950f..2b286de6bd 100644 --- a/src/backup.c +++ b/src/backup.c @@ -123,7 +123,7 @@ static int setDestPgsz(sqlite3_backup *p){ ** message in database handle db. */ static int checkReadTransaction(sqlite3 *db, Btree *p){ - if( sqlite3BtreeIsInReadTrans(p) ){ + if( sqlite3BtreeTxnState(p)!=SQLITE_TXN_NONE ){ sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use"); return SQLITE_ERROR; } @@ -354,7 +354,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** one now. If a transaction is opened here, then it will be closed ** before this function exits. */ - if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){ + if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(p->pSrc) ){ rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0); bCloseTrans = 1; } @@ -726,7 +726,7 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ sqlite3BtreeEnter(pTo); sqlite3BtreeEnter(pFrom); - assert( sqlite3BtreeIsInTrans(pTo) ); + assert( sqlite3BtreeTxnState(pTo)==SQLITE_TXN_WRITE ); pFd = sqlite3PagerFile(sqlite3BtreePager(pTo)); if( pFd->pMethods ){ i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom); @@ -762,7 +762,7 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ sqlite3PagerClearCache(sqlite3BtreePager(b.pDest)); } - assert( sqlite3BtreeIsInTrans(pTo)==0 ); + assert( sqlite3BtreeTxnState(pTo)!=SQLITE_TXN_WRITE ); copy_finished: sqlite3BtreeLeave(pFrom); sqlite3BtreeLeave(pTo); diff --git a/src/btree.c b/src/btree.c index 919d3b87cd..4579121697 100644 --- a/src/btree.c +++ b/src/btree.c @@ -10310,11 +10310,12 @@ const char *sqlite3BtreeGetJournalname(Btree *p){ } /* -** Return non-zero if a transaction is active. +** Return one of SQLITE_TXN_NONE, SQLITE_TXN_READ, or SQLITE_TXN_WRITE +** to describe the current transaction state of Btree p. */ -int sqlite3BtreeIsInTrans(Btree *p){ +int sqlite3BtreeTxnState(Btree *p){ assert( p==0 || sqlite3_mutex_held(p->db->mutex) ); - return (p && (p->inTrans==TRANS_WRITE)); + return p ? p->inTrans : 0; } #ifndef SQLITE_OMIT_WAL @@ -10343,14 +10344,8 @@ int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *pnCkpt){ #endif /* -** Return non-zero if a read (or write) transaction is active. +** Return true if there is currently a backup running on Btree p. */ -int sqlite3BtreeIsInReadTrans(Btree *p){ - assert( p ); - assert( sqlite3_mutex_held(p->db->mutex) ); - return p->inTrans!=TRANS_NONE; -} - int sqlite3BtreeIsInBackup(Btree *p){ assert( p ); assert( sqlite3_mutex_held(p->db->mutex) ); diff --git a/src/btree.h b/src/btree.h index 5dd5287d18..4763ee04c4 100644 --- a/src/btree.h +++ b/src/btree.h @@ -85,8 +85,7 @@ int sqlite3BtreeCommit(Btree*); int sqlite3BtreeRollback(Btree*,int,int); int sqlite3BtreeBeginStmt(Btree*,int); int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags); -int sqlite3BtreeIsInTrans(Btree*); -int sqlite3BtreeIsInReadTrans(Btree*); +int sqlite3BtreeTxnState(Btree*); int sqlite3BtreeIsInBackup(Btree*); void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); int sqlite3BtreeSchemaLocked(Btree *pBtree); diff --git a/src/btreeInt.h b/src/btreeInt.h index c6dfa27ef5..bffe09b617 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -364,11 +364,25 @@ struct Btree { ** If the shared-data extension is enabled, there may be multiple users ** of the Btree structure. At most one of these may open a write transaction, ** but any number may have active read transactions. +** +** These values must match SQLITE_TXN_NONE, SQLITE_TXN_READ, and +** SQLITE_TXN_WRITE */ #define TRANS_NONE 0 #define TRANS_READ 1 #define TRANS_WRITE 2 +#if TRANS_NONE!=SQLITE_TXN_NONE +# error wrong numeric code for no-transaction +#endif +#if TRANS_READ!=SQLITE_TXN_READ +# error wrong numeric code for read-transaction +#endif +#if TRANS_WRITE!=SQLITE_TXN_WRITE +# error wrong numeric code for write-transaction +#endif + + /* ** An instance of this object represents a single database file. ** diff --git a/src/main.c b/src/main.c index 831e06e933..917028c7bf 100644 --- a/src/main.c +++ b/src/main.c @@ -897,7 +897,7 @@ int sqlite3_db_cacheflush(sqlite3 *db){ sqlite3BtreeEnterAll(db); for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; - if( pBt && sqlite3BtreeIsInTrans(pBt) ){ + if( pBt && sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ Pager *pPager = sqlite3BtreePager(pBt); rc = sqlite3PagerFlush(pPager); if( rc==SQLITE_BUSY ){ @@ -1241,6 +1241,36 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){ return SQLITE_OK; } +/* +** Return the transaction state for a single databse, or the maximum +** transaction state over all attached databases if zSchema is null. +*/ +int sqlite3_txn_state(sqlite3 *db, const char *zSchema){ + int iDb, nDb; + int iTxn = -1; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return -1; + } +#endif + sqlite3_mutex_enter(db->mutex); + if( zSchema ){ + nDb = iDb = sqlite3FindDbName(db, zSchema); + if( iDb<0 ) nDb--; + }else{ + iDb = 0; + nDb = db->nDb-1; + } + for(; iDb<=nDb; iDb++){ + Btree *pBt = db->aDb[iDb].pBt; + int x = pBt!=0 ? sqlite3BtreeTxnState(pBt) : SQLITE_TXN_NONE; + if( x>iTxn ) iTxn = x; + } + sqlite3_mutex_leave(db->mutex); + return iTxn; +} + /* ** Two variations on the public interface for closing a database ** connection. The sqlite3_close() version returns SQLITE_BUSY and @@ -1401,7 +1431,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ for(i=0; inDb; i++){ Btree *p = db->aDb[i].pBt; if( p ){ - if( sqlite3BtreeIsInTrans(p) ){ + if( sqlite3BtreeTxnState(p)==SQLITE_TXN_WRITE ){ inTrans = 1; } sqlite3BtreeRollback(p, tripCode, !schemaChange); @@ -4440,7 +4470,7 @@ int sqlite3_snapshot_get( int iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; - if( 0==sqlite3BtreeIsInTrans(pBt) ){ + if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); @@ -4476,10 +4506,10 @@ int sqlite3_snapshot_open( iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; - if( sqlite3BtreeIsInTrans(pBt)==0 ){ + if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ){ Pager *pPager = sqlite3BtreePager(pBt); int bUnlock = 0; - if( sqlite3BtreeIsInReadTrans(pBt) ){ + if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_NONE ){ if( db->nVdbeActive==0 ){ rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot); if( rc==SQLITE_OK ){ @@ -4528,7 +4558,7 @@ int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){ iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; - if( 0==sqlite3BtreeIsInReadTrans(pBt) ){ + if( SQLITE_TXN_NONE==sqlite3BtreeTxnState(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt)); diff --git a/src/pragma.c b/src/pragma.c index 97ad5ac90b..df7d2c943b 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -131,7 +131,9 @@ static int getTempStore(const char *z){ static int invalidateTempStorage(Parse *pParse){ sqlite3 *db = pParse->db; if( db->aDb[1].pBt!=0 ){ - if( !db->autoCommit || sqlite3BtreeIsInReadTrans(db->aDb[1].pBt) ){ + if( !db->autoCommit + || sqlite3BtreeTxnState(db->aDb[1].pBt)!=SQLITE_TXN_NONE + ){ sqlite3ErrorMsg(pParse, "temporary storage cannot be changed " "from within a transaction"); return SQLITE_ERROR; diff --git a/src/prepare.c b/src/prepare.c index 8e2186b102..dac12d8a5b 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -240,7 +240,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){ ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed before this function returns. */ sqlite3BtreeEnter(pDb->pBt); - if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){ + if( sqlite3BtreeTxnState(pDb->pBt)==SQLITE_TXN_NONE ){ rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0); if( rc!=SQLITE_OK ){ sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc)); @@ -483,7 +483,7 @@ static void schemaIsValid(Parse *pParse){ /* If there is not already a read-only (or read-write) transaction opened ** on the b-tree database, open one now. If a transaction is opened, it ** will be closed immediately after reading the meta-value. */ - if( !sqlite3BtreeIsInReadTrans(pBt) ){ + if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_NONE ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index dbcc0e9893..9a372d32bb 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6186,6 +6186,57 @@ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName); */ int sqlite3_db_readonly(sqlite3 *db, const char *zDbName); +/* +** CAPI3REF: Determine the transaction state of a database +** METHOD: sqlite3 +** +** ^The sqlite3_txn_state(D,S) interface returns the current +** [transaction state] of schema S in database connection D. ^If S is NULL, +** then the highest transaction state of any schema on databse connection D +** is returned. Transaction states are (in order of lowest to highest): +**
    +**
  1. SQLITE_TXN_NONE +**
  2. SQLITE_TXN_READ +**
  3. SQLITE_TXN_WRITE +**
+** ^If the S argument to sqlite3_txn_state(D,S) is in the name of +** a valid schema, then -1 is returned. +*/ +int sqlite3_txn_state(sqlite3*,const char *zSchema); + +/* +** CAPI3REF: Allowed return values from [sqlite3_txn_state()] +** KEYWORDS: {transaction state} +** +** These constants define the current transaction state of a database file. +** ^The [sqlite3_txn_state(D,S)] interface returns one of these +** constants in order to describe the transaction state of schema S +** in [database connection] D. +** +**
+** [[SQLITE_TXN_NONE]]
SQLITE_TXN_NONE
+**
The SQLITE_TXN_NONE state means that no transaction is currently +** pending.
+** +** [[SQLITE_TXN_READ]]
SQLITE_TXN_READ
+**
The SQLITE_TXN_READ state means that the database is currently +** in a read transaction. Content has been read from the database file +** but nothing in the database file has changed. The transaction state +** will advanced to SQLITE_TXN_WRITE if any changes occur and there are +** no other conflicting concurrent write transactions. The transaction +** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or +** [COMMIT].
+** +** [[SQLITE_TXN_WRITE]]
SQLITE_TXN_WRITE
+**
The SQLITE_TXN_WRITE state means that the database is currently +** in a write transaction. Content has been written to the database file +** but has not yet committed. The transaction state will change to +** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].
+*/ +#define SQLITE_TXN_NONE 0 +#define SQLITE_TXN_READ 1 +#define SQLITE_TXN_WRITE 2 + /* ** CAPI3REF: Find the next prepared statement ** METHOD: sqlite3 @@ -9345,6 +9396,7 @@ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** CAPI3REF: Flush caches to disk mid-transaction +** METHOD: sqlite3 ** ** ^If a write-transaction is open on [database connection] D when the ** [sqlite3_db_cacheflush(D)] interface invoked, any dirty @@ -9377,6 +9429,7 @@ int sqlite3_db_cacheflush(sqlite3*); /* ** CAPI3REF: The pre-update hook. +** METHOD: sqlite3 ** ** ^These interfaces are only available if SQLite is compiled using the ** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option. @@ -9479,6 +9532,7 @@ int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **); /* ** CAPI3REF: Low-level system error code +** METHOD: sqlite3 ** ** ^Attempt to return the underlying operating system error code or error ** number that caused the most recent I/O error or failure to open a file. diff --git a/src/test1.c b/src/test1.c index 9904402108..04b9f7a011 100644 --- a/src/test1.c +++ b/src/test1.c @@ -7749,6 +7749,33 @@ static int SQLITE_TCLAPI test_sqlite3_db_config( Tcl_SetObjResult(interp, Tcl_NewIntObj(v)); return TCL_OK; } +/* +** tclcmd: sqlite3_txn_state DB ?SCHEMA? +** +** Invoke sqlite3_txn_state(DB,SCHEMA) and return the +** numeric value that results. Use NULL for SCHEMA if the 3 argument +** is omitted. +*/ +static int SQLITE_TCLAPI test_sqlite3_txn_state( + void *clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3 *db; + const char *zSchema; + int iTxn; + + if( objc!=2 && objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "DB ?SCHEMA?"); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + zSchema = objc==3 ? Tcl_GetString(objv[2]) : 0; + iTxn = sqlite3_txn_state(db, zSchema); + Tcl_SetObjResult(interp, Tcl_NewIntObj(iTxn)); + return TCL_OK; +} /* ** Change the name of the main database schema from "main" to "icecube". @@ -7985,6 +8012,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ void *clientData; } aObjCmd[] = { { "sqlite3_db_config", test_sqlite3_db_config, 0 }, + { "sqlite3_txn_state", test_sqlite3_txn_state, 0 }, { "bad_behavior", test_bad_behavior, (void*)&iZero }, { "register_dbstat_vtab", test_register_dbstat_vtab }, { "sqlite3_connection_pointer", get_sqlite_pointer, 0 }, diff --git a/src/vacuum.c b/src/vacuum.c index 50875d8d3d..93e2307d1a 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -339,8 +339,8 @@ SQLITE_NOINLINE int sqlite3RunVacuum( BTREE_APPLICATION_ID, 0, /* Preserve the application id */ }; - assert( 1==sqlite3BtreeIsInTrans(pTemp) ); - assert( pOut!=0 || 1==sqlite3BtreeIsInTrans(pMain) ); + assert( SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pTemp) ); + assert( pOut!=0 || SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pMain) ); /* Copy Btree meta values */ for(i=0; ip2 && (db->autoCommit==0 || db->nVdbeRead>1) ){ - assert( sqlite3BtreeIsInTrans(pBt) ); + assert( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ); if( p->iStatement==0 ){ assert( db->nStatement>=0 && db->nSavepoint>=0 ); db->nStatement++; @@ -7038,7 +7038,7 @@ case OP_JournalMode: { /* out2 */ /* Open a transaction on the database file. Regardless of the journal ** mode, this transaction always uses a rollback journal. */ - assert( sqlite3BtreeIsInTrans(pBt)==0 ); + assert( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ); if( rc==SQLITE_OK ){ rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 5f8b8a817b..5dff54fc85 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2663,7 +2663,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ */ for(i=0; rc==SQLITE_OK && inDb; i++){ Btree *pBt = db->aDb[i].pBt; - if( sqlite3BtreeIsInTrans(pBt) ){ + if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ /* Whether or not a database might need a super-journal depends upon ** its journal mode (among other things). This matrix determines which ** journal modes use a super-journal and which do not */ @@ -2798,7 +2798,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ */ for(i=0; inDb; i++){ Btree *pBt = db->aDb[i].pBt; - if( sqlite3BtreeIsInTrans(pBt) ){ + if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){ char const *zFile = sqlite3BtreeGetJournalname(pBt); if( zFile==0 ){ continue; /* Ignore TEMP and :memory: databases */ diff --git a/test/trans.test b/test/trans.test index bbaedc5450..6b8ad217a0 100644 --- a/test/trans.test +++ b/test/trans.test @@ -11,7 +11,6 @@ # This file implements regression tests for SQLite library. The # focus of this script is database locks. # -# $Id: trans.test,v 1.41 2009/04/28 16:37:59 danielk1977 Exp $ set testdir [file dirname $argv0] @@ -39,6 +38,19 @@ do_test trans-1.1 { SELECT b FROM two ORDER BY a; } } {I V X} +do_test trans-1.2.1 { + sqlite3_txn_state db +} {0} +do_test trans-1.2.2 { + sqlite3_txn_state db main +} {0} +do_test trans-1.2.3 { + sqlite3_txn_state db temp +} {0} +do_test trans-1.2.4 { + sqlite3_txn_state db no-such-schema +} {-1} + do_test trans-1.9 { sqlite3 altdb test.db execsql {SELECT b FROM one ORDER BY a} altdb @@ -55,6 +67,9 @@ do_test trans-2.1 { set v [catch {execsql {BEGIN}} msg] lappend v $msg } {0 {}} +do_test trans-2.1b { + sqlite3_txn_state db +} {0} do_test trans-2.2 { set v [catch {execsql {END}} msg] lappend v $msg @@ -95,6 +110,16 @@ do_test trans-3.1 { SELECT a FROM one ORDER BY a; } } {1 2 3} +do_test trans-3.1b { + sqlite3_txn_state db +} {2} +do_test trans-3.1c { + sqlite3_txn_state db main +} {2} +do_test trans-3.1d { + sqlite3_txn_state db temp +} {0} + do_test trans-3.2 { catchsql { SELECT a FROM two ORDER BY a; @@ -139,6 +164,10 @@ do_test trans-3.9 { do_test trans-3.10 { execsql {END TRANSACTION} } {} +do_test trans-3.10b { + sqlite3_txn_state db +} {0} + do_test trans-3.11 { set v [catch {execsql { @@ -252,6 +281,15 @@ do_test trans-5.2 { execsql {BEGIN TRANSACTION} execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} } {} +do_test trans-5.2b { + sqlite3_txn_state db +} {1} +do_test trans-5.2c { + sqlite3_txn_state db main +} {1} +do_test trans-5.2d { + sqlite3_txn_state db temp +} {0} do_test trans-5.3 { execsql {CREATE TABLE one(a text, b int)} execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}