]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add locks to the in-memory database so that recursive writes will be detected
authordrh <drh@noemail.net>
Wed, 27 Aug 2003 22:52:34 +0000 (22:52 +0000)
committerdrh <drh@noemail.net>
Wed, 27 Aug 2003 22:52:34 +0000 (22:52 +0000)
and rejected.  Ticket #436. (CVS 1090)

FossilOrigin-Name: 966b1a16f6687df08f8c21787c1c8b1af1d79e1e

manifest
manifest.uuid
src/btree_rb.c

index 94816ae4f88368f427f43368d32e69cc5c5fd03b..6c33a555677982c71c19eb3dddccbd7f19397157 100644 (file)
--- 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
index 87e76a2f936fe5d6af50d8f4acc3b798cf04ee3e..60b81cd31acb7dade478904c4fd77437fc6c7511 100644 (file)
@@ -1 +1 @@
-c95f347cac27732533a2f6fd4ba50bf00eef59f3
\ No newline at end of file
+966b1a16f6687df08f8c21787c1c8b1af1d79e1e
\ No newline at end of file
index 24687595833af1e11ff8156c10240db843f4630e..d03705b9d427466451e1098a2bb015ecacd0c8e0 100644 (file)
@@ -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: