diff --git a/manifest b/manifest index 94816ae4f8..6c33a55567 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\scompiler\swarnings\sunder\sOpenVMS.\s\sTicket\s#357.\s(CVS\s1088) -D 2003-08-26T11:41:27 +C Add\slocks\sto\sthe\sin-memory\sdatabase\sso\sthat\srecursive\swrites\swill\sbe\sdetected\nand\srejected.\s\sTicket\s#436.\s(CVS\s1090) +D 2003-08-27T22:52:34 F Makefile.in f7e916ae863393827fa6a4cb292e3398096edcf1 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -23,7 +23,7 @@ F src/attach.c 9f78b4aaac02a2b09ff108e92cbaee3199e7962a F src/auth.c c8f50d4507e37779d96ff3c55417bc2b612dfed6 F src/btree.c ba1cc0c71c3d2742b9a9047832335dc7d3656c45 F src/btree.h 9b7c09f1e64274d7bb74a57bbfc63778f67b1048 -F src/btree_rb.c f30f5cddc4375c05bf361116da1492d9601760ca +F src/btree_rb.c 2f7ee4fa951d761c470ffadbf691883717a1efe7 F src/build.c 7cdc95266496f53673a66202477b137d514898cf F src/copy.c 9e47975ea96751c658bcf1a0c4f0bb7c6ee61e73 F src/delete.c 0f81e6799c089487615d38e042a2de4d2d6192bc @@ -168,7 +168,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 -P cbe32216966c987902ceb4d85332fc95801dbda2 -R ddd7131f94b88ef749e9dcf2a2026ce5 +P c95f347cac27732533a2f6fd4ba50bf00eef59f3 +R 002b3717598c8349a2d682847ae9c09b U drh -Z bc22588721b74c4fdc0bad5666b4494e +Z 4b1d0cc8167eef257f9d48654435d622 diff --git a/manifest.uuid b/manifest.uuid index 87e76a2f93..60b81cd31a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c95f347cac27732533a2f6fd4ba50bf00eef59f3 \ No newline at end of file +966b1a16f6687df08f8c21787c1c8b1af1d79e1e \ No newline at end of file diff --git a/src/btree_rb.c b/src/btree_rb.c index 2468759583..d03705b9d4 100644 --- a/src/btree_rb.c +++ b/src/btree_rb.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree_rb.c,v 1.14 2003/06/29 18:29:48 drh Exp $ +** $Id: btree_rb.c,v 1.15 2003/08/27 22:52:34 drh Exp $ ** ** This file implements an in-core database using Red-Black balanced ** binary trees. @@ -99,7 +99,9 @@ struct RbtCursor { BtRbTree *pTree; int iTree; /* Index of pTree in pRbtree */ BtRbNode *pNode; + RbtCursor *pShared; /* List of all cursors on the same Rbtree */ u8 eSkip; /* Determines if next step operation is a no-op */ + u8 wrFlag; /* True if this cursor is open for writing */ }; /* @@ -111,7 +113,8 @@ struct RbtCursor { #define SKIP_INVALID 3 /* Calls to Next() and Previous() are invalid */ struct BtRbTree { - BtRbNode *pHead; /* Head of the tree, or NULL */ + RbtCursor *pCursors; /* All cursors pointing to this tree */ + BtRbNode *pHead; /* Head of the tree, or NULL */ }; struct BtRbNode { @@ -139,6 +142,33 @@ static int memRbtreeNext(RbtCursor* pCur, int *pRes); static int memRbtreeLast(RbtCursor* pCur, int *pRes); static int memRbtreePrevious(RbtCursor* pCur, int *pRes); + +/* +** This routine checks all cursors that point to the same table +** as pCur points to. If any of those cursors were opened with +** wrFlag==0 then this routine returns SQLITE_LOCKED. If all +** cursors point to the same table were opened with wrFlag==1 +** then this routine returns SQLITE_OK. +** +** In addition to checking for read-locks (where a read-lock +** means a cursor opened with wrFlag==0) this routine also NULLs +** out the pNode field of all other cursors. +** This is necessary because an insert +** or delete might change erase the node out from under +** another cursor. +*/ +static int checkReadLocks(RbtCursor *pCur){ + RbtCursor *p; + assert( pCur->wrFlag ); + for(p=pCur->pTree->pCursors; p; p=p->pShared){ + if( p!=pCur ){ + if( p->wrFlag==0 ) return SQLITE_LOCKED; + p->pNode = 0; + } + } + return SQLITE_OK; +} + /* * The key-compare function for the red-black trees. Returns as follows: * @@ -636,6 +666,7 @@ static int memRbtreeDropTable(Rbtree* tree, int n) memRbtreeClearTable(tree, n); pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0); assert(pTree); + assert( pTree->pCursors==0 ); sqliteFree(pTree); if( tree->eTransState != TRANS_ROLLBACK ){ @@ -668,7 +699,7 @@ static int memRbtreeKeyCompare(RbtCursor* pCur, const void *pKey, int nKey, /* * Get a new cursor for table iTable of the supplied Rbtree. The wrFlag - * parameter is ignored, all cursors are capable of write-operations. + * parameter indicates that the cursor is open for writing. * * Note that RbtCursor.eSkip and RbtCursor.pNode both initialize to 0. */ @@ -678,12 +709,17 @@ static int memRbtreeCursor( int wrFlag, RbtCursor **ppCur ){ + RbtCursor *pCur; assert(tree); - *ppCur = sqliteMalloc(sizeof(RbtCursor)); - (*ppCur)->pTree = sqliteHashFind(&tree->tblHash, 0, iTable); - (*ppCur)->pRbtree = tree; - (*ppCur)->iTree = iTable; - (*ppCur)->pOps = &sqliteRbtreeCursorOps; + pCur = *ppCur = sqliteMalloc(sizeof(RbtCursor)); + pCur->pTree = sqliteHashFind(&tree->tblHash, 0, iTable); + pCur->pRbtree = tree; + pCur->iTree = iTable; + pCur->pOps = &sqliteRbtreeCursorOps; + pCur->wrFlag = wrFlag; + pCur->pShared = pCur->pTree->pCursors; + pCur->pTree->pCursors = pCur; + assert( (*ppCur)->pTree ); return SQLITE_OK; @@ -711,6 +747,11 @@ static int memRbtreeInsert( ** not in a transaction */ assert( pCur->pRbtree->eTransState != TRANS_NONE ); + /* Make sure some other cursor isn't trying to read this same table */ + if( checkReadLocks(pCur) ){ + return SQLITE_LOCKED; /* The table pCur points to has a read lock */ + } + /* Take a copy of the input data now, in case we need it for the * replace case */ pData = sqliteMalloc(nData); @@ -869,6 +910,11 @@ static int memRbtreeDelete(RbtCursor* pCur) ** not in a transaction */ assert( pCur->pRbtree->eTransState != TRANS_NONE ); + /* Make sure some other cursor isn't trying to read this same table */ + if( checkReadLocks(pCur) ){ + return SQLITE_LOCKED; /* The table pCur points to has a read lock */ + } + pZ = pCur->pNode; if( !pZ ){ return SQLITE_OK; @@ -1146,6 +1192,16 @@ static int memRbtreeData(RbtCursor *pCur, int offset, int amt, char *zBuf) static int memRbtreeCloseCursor(RbtCursor* pCur) { + if( pCur->pTree->pCursors==pCur ){ + pCur->pTree->pCursors = pCur->pShared; + }else{ + RbtCursor *p = pCur->pTree->pCursors; + while( p && p->pShared!=pCur ){ p = p->pShared; } + assert( p!=0 ); + if( p ){ + p->pShared = pCur->pShared; + } + } sqliteFree(pCur); return SQLITE_OK; } @@ -1249,6 +1305,7 @@ static void execute_rollback_list(Rbtree *pRbtree, BtRollbackOp *pList) int res; cur.pRbtree = pRbtree; + cur.wrFlag = 1; while( pList ){ switch( pList->eOp ){ case ROLLBACK_INSERT: