diff --git a/manifest b/manifest index 9dd0e53723..351ed714df 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sthe\s\sclause\sfrom\sBEGIN\s(CVS\s1501) -D 2004-05-31T08:55:34 +C Add\sread-transactions\sto\sthe\sbtree\sand\svdbe.\sThe\scompiler\sdoesn't\sinvoke\nthem\syet.\s(CVS\s1502) +D 2004-05-31T10:01:35 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -24,9 +24,9 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79 -F src/btree.c 07d0d93ba0e6f54a0f67e665d264b0bc6ab70edb -F src/btree.h 61d670f418fa6bd88b6d2731f05fcf8b19d3ec45 -F src/build.c 774193e2fb0d1e6492735bcc909d525898c61204 +F src/btree.c 652efb14a17ba26759f73ca167f7d1e5d6651eb3 +F src/btree.h 1e2beb41b4b4a4fc41da67cb4692614938066f2f +F src/build.c 8fd4c1a7df5761ff95dd0e57e82b2c08ab88bbce F src/date.c 0eb922af5c5f5e2455f8dc2f98023ed3e04a857e F src/delete.c 72f8febf6170cda830f509c8f9dffbed3df3596c F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 @@ -60,7 +60,7 @@ F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 F src/tclsqlite.c b314f12760547e4ef090e055f1298f70627450d3 F src/test1.c 32934478366531503d634968db414df17cb38238 F src/test2.c 6195a1ca2c8d0d2d93644e86da3289b403486872 -F src/test3.c 48f14101bde4be18b351a6db977cc30b349bf1c0 +F src/test3.c 86117b74ec7353d76f5cd85c144c7cda23a7e11b F src/test4.c 34848a9fd31aa65857b20a8bfc03aff77d8c3426 F src/test5.c 9a1f15133f6955f067c5246e564723b5f23ff221 F src/tokenize.c 50a87c7414de54a008427c9fed22e4e86efb6844 @@ -68,12 +68,12 @@ F src/trigger.c 04b2c310d0d056b213609cab6df5fff03d5eaf88 F src/update.c 259f06e7b22c684b2d3dda54a18185892d6e9573 F src/utf.c f8604999a54483533ac20a63879074f01b0df384 F src/util.c 3b647719c0bece41491300b605cff96a7a26f03a -F src/vacuum.c 16d1b4ab976f19f01aa626bfdac9fee5e2cce03c -F src/vdbe.c 3cc9b3ab6c4e5b10168d56f09b6864ccb5b50f81 +F src/vacuum.c c91acc316127411980982938d050b299d42b81ef +F src/vdbe.c fdb990a681d39872047fec65fffaedb7225e7420 F src/vdbe.h e73f890e0f2a6c42b183d7d6937947930fe4fdeb F src/vdbeInt.h 51d37798ba7bc5f2f767db0e3dbae31156ae9ff3 F src/vdbeapi.c d43d36efeaf709bae71b743aaaee430e0b29cd1e -F src/vdbeaux.c 9cad713e47e6e684852dfc12ef6e326fb4a2ca76 +F src/vdbeaux.c 32ff5754d489b8e7dd4fa53762e6c02d028cb7d9 F src/vdbemem.c 627d714c347f6af8092cc48ae1c06fd774a1ad9c F src/where.c 444a7c3a8b1eb7bba072e489af628555d21d92a4 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 @@ -204,7 +204,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P b8ed812c92f2dbb4431d45aeb41646ceb53e0cbc -R 0a7b9b75e1ce69dd86720403c073375e +P 9029274b6129140064bd7ac34df7eaba00d28efb +R e95c108b61d714bdf621bb4346f565fc U danielk1977 -Z 97096496cbbd5e8936b9c4165e249994 +Z 566da064bb78af6ca09baccb5cb6e57b diff --git a/manifest.uuid b/manifest.uuid index b652e81cff..3ecb91cf65 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9029274b6129140064bd7ac34df7eaba00d28efb \ No newline at end of file +6b43633a96c674a5d470578ef80ebf2227da0682 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 86b98d6718..ac526ef2dd 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.153 2004/05/31 08:26:49 danielk1977 Exp $ +** $Id: btree.c,v 1.154 2004/05/31 10:01:35 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -316,6 +316,13 @@ struct Btree { }; typedef Btree Bt; +/* +** Btree.inTrans may take one of the following values. +*/ +#define TRANS_NONE 0 +#define TRANS_READ 1 +#define TRANS_WRITE 2 + /* ** An instance of the following structure is used to hold information ** about a cell. The parseCellPtr() function fills in this structure @@ -1142,10 +1149,9 @@ page1_init_failed: ** If there is a transaction in progress, this routine is a no-op. */ static void unlockBtreeIfUnused(Btree *pBt){ - if( pBt->inTrans==0 && pBt->pCursor==0 && pBt->pPage1!=0 ){ + if( pBt->inTrans==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){ releasePage(pBt->pPage1); pBt->pPage1 = 0; - pBt->inTrans = 0; pBt->inStmt = 0; } } @@ -1179,11 +1185,13 @@ static int newDatabase(Btree *pBt){ } /* -** Attempt to start a new transaction. +** Attempt to start a new transaction. A write-transaction +** is started if the second argument is true, otherwise a read- +** transaction. ** -** A transaction must be started before attempting any changes -** to the database. None of the following routines will work -** unless a transaction is started first: +** A write-transaction must be started before attempting any +** changes to the database. None of the following routines +** will work unless a transaction is started first: ** ** sqlite3BtreeCreateTable() ** sqlite3BtreeCreateIndex() @@ -1193,23 +1201,35 @@ static int newDatabase(Btree *pBt){ ** sqlite3BtreeDelete() ** sqlite3BtreeUpdateMeta() */ -int sqlite3BtreeBeginTrans(Btree *pBt){ - int rc; - if( pBt->inTrans ) return SQLITE_ERROR; - if( pBt->readOnly ) return SQLITE_READONLY; +int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){ + int rc = SQLITE_OK; + + /* If the btree is already in a write-transaction, or it + ** is already in a read-transaction and a read-transaction + ** is requested, this is a no-op. + */ + if( pBt->inTrans==TRANS_WRITE || + (pBt->inTrans==TRANS_READ && !wrflag) ){ + return SQLITE_OK; + } + if( pBt->readOnly && wrflag ){ + return SQLITE_READONLY; + } + if( pBt->pPage1==0 ){ rc = lockBtree(pBt); - if( rc!=SQLITE_OK ){ - return rc; + } + + if( rc==SQLITE_OK && wrflag ){ + rc = sqlite3pager_begin(pBt->pPage1->aData); + if( rc==SQLITE_OK ){ + rc = newDatabase(pBt); } } - rc = sqlite3pager_begin(pBt->pPage1->aData); + if( rc==SQLITE_OK ){ - rc = newDatabase(pBt); - } - if( rc==SQLITE_OK ){ - pBt->inTrans = 1; - pBt->inStmt = 0; + pBt->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); + if( wrflag ) pBt->inStmt = 0; }else{ unlockBtreeIfUnused(pBt); } @@ -1223,9 +1243,11 @@ int sqlite3BtreeBeginTrans(Btree *pBt){ ** are no active cursors, it also releases the read lock. */ int sqlite3BtreeCommit(Btree *pBt){ - int rc; - rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_commit(pBt->pPager); - pBt->inTrans = 0; + int rc = SQLITE_OK; + if( pBt->inTrans==TRANS_WRITE ){ + rc = sqlite3pager_commit(pBt->pPager); + } + pBt->inTrans = TRANS_NONE; pBt->inStmt = 0; unlockBtreeIfUnused(pBt); return rc; @@ -1278,12 +1300,7 @@ void sqlite3BtreeCursorList(Btree *pBt){ int sqlite3BtreeRollback(Btree *pBt){ int rc; MemPage *pPage1; - if( pBt->inTrans==0 ) return SQLITE_OK; - pBt->inTrans = 0; - pBt->inStmt = 0; - if( pBt->readOnly ){ - rc = SQLITE_OK; - }else{ + if( pBt->inTrans==TRANS_WRITE ){ rc = sqlite3pager_rollback(pBt->pPager); /* The rollback may have destroyed the pPage1->aData value. So ** call getPage() on page 1 again to make sure pPage1->aData is @@ -1291,8 +1308,10 @@ int sqlite3BtreeRollback(Btree *pBt){ if( getPage(pBt, 1, &pPage1)==SQLITE_OK ){ releasePage(pPage1); } + invalidateCursors(pBt); } - invalidateCursors(pBt); + pBt->inTrans = TRANS_NONE; + pBt->inStmt = 0; unlockBtreeIfUnused(pBt); return rc; } @@ -1314,7 +1333,7 @@ int sqlite3BtreeRollback(Btree *pBt){ */ int sqlite3BtreeBeginStmt(Btree *pBt){ int rc; - if( !pBt->inTrans || pBt->inStmt ){ + if( (pBt->inTrans!=TRANS_WRITE) || pBt->inStmt ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_stmt_begin(pBt->pPager); @@ -3360,7 +3379,7 @@ int sqlite3BtreeInsert( if( pCur->status ){ return pCur->status; /* A rollback destroyed this cursor */ } - if( !pBt->inTrans ){ + if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction before doing an insert */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } @@ -3427,7 +3446,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ if( pCur->status ){ return pCur->status; /* A rollback destroyed this cursor */ } - if( !pBt->inTrans ){ + if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction before doing a delete */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } @@ -3508,7 +3527,7 @@ int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){ MemPage *pRoot; Pgno pgnoRoot; int rc; - if( !pBt->inTrans ){ + if( pBt->inTrans!=TRANS_WRITE ){ /* Must start a transaction first */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } @@ -3577,7 +3596,7 @@ static int clearDatabasePage( int sqlite3BtreeClearTable(Btree *pBt, int iTable){ int rc; BtCursor *pCur; - if( !pBt->inTrans ){ + if( pBt->inTrans!=TRANS_WRITE ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ @@ -3605,7 +3624,7 @@ int sqlite3BtreeDropTable(Btree *pBt, int iTable){ int rc; MemPage *pPage; BtCursor *pCur; - if( !pBt->inTrans ){ + if( pBt->inTrans!=TRANS_WRITE ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ @@ -3657,7 +3676,7 @@ int sqlite3BtreeUpdateMeta(Btree *pBt, int idx, u32 iMeta){ unsigned char *pP1; int rc; assert( idx>=1 && idx<=15 ); - if( !pBt->inTrans ){ + if( pBt->inTrans!=TRANS_WRITE ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( pBt->pPage1!=0 ); @@ -4153,7 +4172,9 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){ int rc = SQLITE_OK; Pgno i, nPage, nToPage; - if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR; + if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){ + return SQLITE_ERROR; + } if( pBtTo->pCursor ) return SQLITE_BUSY; memcpy(pBtTo->pPage1->aData, pBtFrom->pPage1->aData, pBtFrom->usableSize); rc = sqlite3pager_overwrite(pBtTo->pPager, 1, pBtFrom->pPage1->aData); @@ -4188,7 +4209,7 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){ ** Return non-zero if a transaction is active. */ int sqlite3BtreeIsInTrans(Btree *pBt){ - return (pBt && pBt->inTrans); + return (pBt && (pBt->inTrans==TRANS_WRITE)); } /* diff --git a/src/btree.h b/src/btree.h index c6c4f08bc2..931cca990c 100644 --- a/src/btree.h +++ b/src/btree.h @@ -13,7 +13,7 @@ ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** -** @(#) $Id: btree.h,v 1.50 2004/05/31 08:26:49 danielk1977 Exp $ +** @(#) $Id: btree.h,v 1.51 2004/05/31 10:01:35 danielk1977 Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ @@ -41,7 +41,7 @@ int sqlite3BtreeOpen(const char *zFilename, Btree **, int nCache, int flags); int sqlite3BtreeClose(Btree*); int sqlite3BtreeSetCacheSize(Btree*,int); int sqlite3BtreeSetSafetyLevel(Btree*,int); -int sqlite3BtreeBeginTrans(Btree*); +int sqlite3BtreeBeginTrans(Btree*,int); int sqlite3BtreeCommit(Btree*); int sqlite3BtreeRollback(Btree*); int sqlite3BtreeBeginStmt(Btree*); diff --git a/src/build.c b/src/build.c index 52e7827774..c2ce6a7aab 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.202 2004/05/31 08:55:34 danielk1977 Exp $ +** $Id: build.c,v 1.203 2004/05/31 10:01:35 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -555,8 +555,8 @@ void sqlite3StartTable( pParse->nErr++; return; } - if( db->flags & SQLITE_InTrans ){ - rc = sqlite3BtreeBeginTrans(db->aDb[1].pBt); + if( db->flags & !db->autoCommit ){ + rc = sqlite3BtreeBeginTrans(db->aDb[1].pBt, 1); if( rc!=SQLITE_OK ){ sqlite3ErrorMsg(pParse, "unable to get a write lock on " "the temporary database file"); @@ -2255,7 +2255,7 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; - sqlite3VdbeAddOp(v, OP_Transaction, iDb, 0); + sqlite3VdbeAddOp(v, OP_Transaction, iDb, 1); sqlite3CodeVerifySchema(pParse, iDb); if( setStatement ){ sqlite3VdbeAddOp(v, OP_Statement, iDb, 0); diff --git a/src/test3.c b/src/test3.c index 5c03c7a070..da90cfaaca 100644 --- a/src/test3.c +++ b/src/test3.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test3.c,v 1.40 2004/05/31 08:26:49 danielk1977 Exp $ +** $Id: test3.c,v 1.41 2004/05/31 10:01:35 danielk1977 Exp $ */ #include "sqliteInt.h" #include "pager.h" @@ -129,7 +129,7 @@ static int btree_begin_transaction( return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR; - rc = sqlite3BtreeBeginTrans(pBt); + rc = sqlite3BtreeBeginTrans(pBt, 1); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; diff --git a/src/vacuum.c b/src/vacuum.c index ff0a5b4fbe..d0fca6ea49 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -14,7 +14,7 @@ ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. ** -** $Id: vacuum.c,v 1.19 2004/05/31 08:26:49 danielk1977 Exp $ +** $Id: vacuum.c,v 1.20 2004/05/31 10:01:35 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -196,7 +196,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite *db){ u32 meta; assert( 0==sqlite3BtreeIsInTrans(pMain) ); - rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt); + rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt, 1); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Copy Btree meta values 3 and 4. These correspond to SQL layer meta diff --git a/src/vdbe.c b/src/vdbe.c index 787b0eeffe..390924b5d6 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.351 2004/05/31 08:26:49 danielk1977 Exp $ +** $Id: vdbe.c,v 1.352 2004/05/31 10:01:35 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -2234,7 +2234,7 @@ case OP_AutoCommit: { break; } -/* Opcode: Transaction P1 * * +/* Opcode: Transaction P1 P2 * ** ** Begin a transaction. The transaction ends when a Commit or Rollback ** opcode is encountered. Depending on the ON CONFLICT setting, the @@ -2244,11 +2244,14 @@ case OP_AutoCommit: { ** started. Index 0 is the main database file and index 1 is the ** file used for temporary tables. ** -** A write lock is obtained on the database file when a transaction is -** started. No other process can read or write the file while the -** transaction is underway. Starting a transaction also creates a -** rollback journal. A transaction must be started before any changes -** can be made to the database. +** If P2 is non-zero, then a write-transaction is started. A write lock is +** obtained on the database file when a write-transaction is started. No +** other process can read or write the file while the transaction is +** underway. Starting a transaction also creates a rollback journal. A +** transaction must be started before any changes can be made to the +** database. +** +** If P2 is zero, then a read-lock is obtained on the database file. */ case OP_Transaction: { int busy = 1; @@ -2258,9 +2261,8 @@ case OP_Transaction: { assert( i>=0 && inDb ); pBt = db->aDb[i].pBt; - if( sqlite3BtreeIsInTrans(pBt) ) break; - while( pBt && busy /* && !sqlite3BtreeIsInTrans(pBt) */ ){ - rc = sqlite3BtreeBeginTrans(db->aDb[i].pBt); + while( pBt && busy ){ + rc = sqlite3BtreeBeginTrans(db->aDb[i].pBt, pOp->p2); switch( rc ){ case SQLITE_BUSY: { if( db->xBusyCallback==0 ){ @@ -2526,7 +2528,7 @@ case OP_OpenTemp: { rc = sqlite3BtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt); if( rc==SQLITE_OK ){ - rc = sqlite3BtreeBeginTrans(pCx->pBt); + rc = sqlite3BtreeBeginTrans(pCx->pBt, 1); } if( rc==SQLITE_OK ){ /* If a transient index is required, create it by calling diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 60e785361a..adf9b29de5 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -979,9 +979,9 @@ int sqlite3VdbeReset(Vdbe *p, char **pzErrMsg){ } for(i=0; xFunc && inDb; i++){ + int rc; Btree *pBt = db->aDb[i].pBt; if( sqlite3BtreeIsInTrans(pBt) ){ - int rc; if( db->xCommitCallback && needXcommit ){ if( db->xCommitCallback(db->pCommitArg)!=0 ){ p->rc = SQLITE_CONSTRAINT; @@ -990,9 +990,9 @@ int sqlite3VdbeReset(Vdbe *p, char **pzErrMsg){ } needXcommit = 0; } - rc = xFunc(pBt); - if( p->rc==SQLITE_OK ) p->rc = rc; } + rc = xFunc(pBt); + if( p->rc==SQLITE_OK ) p->rc = rc; }