]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Back out changes allowing writes to tables that have open cursors. (CVS 2133)
authordanielk1977 <danielk1977@noemail.net>
Mon, 22 Nov 2004 10:02:10 +0000 (10:02 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Mon, 22 Nov 2004 10:02:10 +0000 (10:02 +0000)
FossilOrigin-Name: 91acd87e52509a8f78894d0f4b625b54376cac21

manifest
manifest.uuid
src/btree.c
src/delete.c
src/select.c
src/sqliteInt.h
src/update.c
src/where.c

index 9ce0f1c7e9c1713924f0bc60b031b5f9ca11e269..6e2e1927e82310723fd3421ebb6b46ccb3c460ea 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Modify\stest\ssuite\sto\swork\swhen\sSQLITE_OMIT_VIEW\sis\sdefined.\s(CVS\s2132)
-D 2004-11-22T08:43:32
+C Back\sout\schanges\sallowing\swrites\sto\stables\sthat\shave\sopen\scursors.\s(CVS\s2133)
+D 2004-11-22T10:02:10
 F Makefile.in 8291610f5839939a5fbff4dbbf85adb0fe1ac37f
 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1
@@ -29,11 +29,11 @@ F sqlite3.def dbaeb20c153e1d366e8f421b55a573f5dfc00863
 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
 F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689
 F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea
-F src/btree.c 614ac85f810a636d375da58d0e069896eb467b1a
+F src/btree.c edcd4abafe0db11081e4e2db854b17649bec27d9
 F src/btree.h 861e40b759a195ba63819740e484390012cf81ab
 F src/build.c c7dd57fdbb330d65df241277291cad8e58687a46
 F src/date.c 65536e7ea04fdde6e0551264fca15966966e171f
-F src/delete.c be9d039b819f4a5d0fdfaeceace139ba189ef819
+F src/delete.c cf185995e20a61c0fecc2a9a9a3b19bd18bd05b3
 F src/expr.c 511c27a8858ca12614f495c9c90f5d12db11e6c2
 F src/func.c b668e5ad043176049454c95a6a780367a0e8f6bb
 F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
@@ -58,10 +58,10 @@ F src/parse.y 0a4bdfd7b65d9761b41a862d09a17c90c1f526f7
 F src/pragma.c 0b43b8cac4870bfa041bf2ca29d7ce47b76362d6
 F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
-F src/select.c cf4b7952d6d214931c52636ee726f19ee2a275c5
+F src/select.c 7b17db766e669fc85837af50cc110d0988d31ee9
 F src/shell.c e8f4f486cbf6e60d81173146ac8a6522c930fa51
 F src/sqlite.h.in 6d0e82c24ef3f84a10b468119f3943a5dfc806c7
-F src/sqliteInt.h 8f3b4d0e90c294e0e22b20a9f7f32f2523b8894c
+F src/sqliteInt.h d16d54eeefb24b4b1d0e9fa80593bf110a293aab
 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
 F src/tclsqlite.c 7f1a1a678140e6901c8954590ca2aabe50b48f71
 F src/test1.c 21b1cc9358678da579d7aad8f16a40735a837078
@@ -71,7 +71,7 @@ F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
 F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
 F src/tokenize.c 2ad3d1ae1a0a70746db0b31a0a74f58050a3c39a
 F src/trigger.c 0c91b56182560263733e4b035acdb939bd1cf0e2
-F src/update.c 395a2b270dfcbc96c20e40c9cb42b0533768ce30
+F src/update.c 24a605a4250fe4a0b173bedd7132d1892ad27090
 F src/utf.c e45ce11be6922408cd381561721f6cca7d3b992a
 F src/util.c 4a8db4e97a3cfda12ad8dda3e77dd2d00ad1de5e
 F src/vacuum.c d061dd908a9e809c54e40e24a551b1d64abd3d16
@@ -81,7 +81,7 @@ F src/vdbeInt.h 6017100adff362b8dfa37a69e3f1431f084bfa5b
 F src/vdbeapi.c 74be7f96c0a1ac275661f8b32276ac521d9ce37c
 F src/vdbeaux.c dc06bbb8511d07f8d45ed2ea760f35f0736a690c
 F src/vdbemem.c 5876c8abf4374fef671f4fd8dc333ef3fc95a2f0
-F src/where.c 4d28167e450255372b45abf1bc8cd5f0e9264d7b
+F src/where.c f8a9e0bca6cb0a6fc4c189ed9fa771e75ad68bc8
 F test/all.test 929bfa932b55e75c96fe2203f7650ba451c1862c
 F test/alter.test 2b4478c4906e4d1504b1a121b4ffbc8d11043b53
 F test/attach.test bb0ff048b0a65ca2bd5f186eee05d2ec084f3972
@@ -261,7 +261,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25
 F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618
 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
 F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c
-P 9df837c03939cdcb31856ac17b2425a6dd92d7b2
-R 58a8d6a23d66b3c503089009ebe0b762
+P 711e8d7695dfc74b3f1ee00591dcdda2cd7fc7d5
+R 435be4c4df18ad02a5220daa06c920af
 U danielk1977
-Z 2746b3ff0377ed15d41d60a317d903c0
+Z 690d6154f35eb3573c00acd3211a6213
index d4dd8085f8e5437dc1f483bf86d86d91b3f05a00..0500a7a6a73e80b643fdb47b8c808cfd8c0c2093 100644 (file)
@@ -1 +1 @@
-711e8d7695dfc74b3f1ee00591dcdda2cd7fc7d5
\ No newline at end of file
+91acd87e52509a8f78894d0f4b625b54376cac21
\ No newline at end of file
index ba2bda3ab4fab559564b56b88b06ec97d070fabd..d73166f7f4a249136ef0114021c273c355337f87 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.222 2004/11/22 05:26:27 danielk1977 Exp $
+** $Id: btree.c,v 1.223 2004/11/22 10:02:10 danielk1977 Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -344,16 +344,6 @@ struct CellInfo {
 ** A cursor is a pointer to a particular entry in the BTree.
 ** The entry is identified by its MemPage and the index in
 ** MemPage.aCell[] of the entry.
-**
-** Normally, the BtCursor.delShift variable is 0. If non-zero, this
-** indicates that the entry to which the cursor logically points 
-** was deleted (by a BtreeDelete() call). If this is the case, the
-** BtreeKeySize() and BtreeDataSize() calls both return 0. 
-
-** If BtCursor.delShift is +1, then do not move the cursor for a 
-** BtreeNext() operation (it was already advanced when the entry the
-** cursor logically points to was deleted). If BtCursor.delShift is
-** -1, then ignore the next BtreePrevious() call.
 */
 struct BtCursor {
   Btree *pBt;               /* The Btree to which this cursor belongs */
@@ -367,7 +357,6 @@ struct BtCursor {
   u8 wrFlag;                /* True if writable */
   u8 isValid;               /* TRUE if points to a valid entry */
   u8 status;                /* Set to SQLITE_ABORT if cursors is invalidated */
-  int delShift;             /* See above. */
 };
 
 /*
@@ -2125,7 +2114,6 @@ int sqlite3BtreeCursor(
   pBt->pCursor = pCur;
   pCur->isValid = 0;
   pCur->status = SQLITE_OK;
-  pCur->delShift = 0;
   *ppCur = pCur;
   return SQLITE_OK;
 
@@ -2224,7 +2212,7 @@ static void getCellInfo(BtCursor *pCur){
 ** itself, not the number of bytes in the key.
 */
 int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
-  if( !pCur->isValid || pCur->delShift ){
+  if( !pCur->isValid ){
     *pSize = 0;
   }else{
     getCellInfo(pCur);
@@ -2241,7 +2229,7 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
 ** the database is empty) then *pSize is set to 0.
 */
 int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
-  if( !pCur->isValid || pCur->delShift ){
+  if( !pCur->isValid ){
     /* Not pointing at a valid entry - set *pSize to 0. */
     *pSize = 0;
   }else{
@@ -2352,7 +2340,7 @@ static int getPayload(
 ** the available payload.
 */
 int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
-  if( !pCur->isValid || pCur->delShift ){
+  if( !pCur->isValid ){
     return pCur->status;
   }
   assert( pCur->pPage!=0 );
@@ -2371,7 +2359,7 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
 ** the available payload.
 */
 int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
-  if( !pCur->isValid || pCur->delShift ){
+  if( !pCur->isValid ){
     return pCur->status ? pCur->status : SQLITE_INTERNAL;
   }
   assert( pCur->pPage!=0 );
@@ -2559,7 +2547,6 @@ static int moveToRoot(BtCursor *pCur){
     rc = moveToChild(pCur, subpage);
   }
   pCur->isValid = pCur->pPage->nCell>0;
-  pCur->delShift = 0;
   return rc;
 }
 
@@ -2797,15 +2784,6 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
   assert( pPage->isInit );
   assert( pCur->idx<pPage->nCell );
 
-  /* If BtCursor.delShift is 1, the cursor has already been advanced. */
-  if( pCur->delShift==1 ){
-    *pRes = 0;
-    pCur->delShift = 0;
-    return SQLITE_OK;
-  }else{
-    pCur->delShift = 0;
-  }
-
   pCur->idx++;
   pCur->info.nSize = 0;
   if( pCur->idx>=pPage->nCell ){
@@ -2856,15 +2834,6 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
     return SQLITE_OK;
   }
 
-  /* If BtCursor.delShift is -1, the cursor has already been advanced. */
-  if( pCur->delShift==-1 ){
-    *pRes = 0;
-    pCur->delShift = 0;
-    return SQLITE_OK;
-  }else{
-    pCur->delShift = 0;
-  }
-
   pPage = pCur->pPage;
   assert( pPage->isInit );
   assert( pCur->idx>=0 );
@@ -3656,7 +3625,6 @@ static int balance_nonroot(MemPage *pPage){
   int *szCell;                 /* Local size of all cells in apCell[] */
   u8 *aCopy[NB];               /* Space for holding data of apCopy[] */
   u8 *aSpace;                  /* Space to hold copies of dividers cells */
-  BtCursor *pCur;
 
   /* 
   ** Find the parent page.
@@ -3905,6 +3873,16 @@ static int balance_nonroot(MemPage *pPage){
     zeroPage(pNew, pageFlags);
   }
 
+  /* Free any old pages that were not reused as new pages.
+  */
+  while( i<nOld ){
+    rc = freePage(apOld[i]);
+    if( rc ) goto balance_cleanup;
+    releasePage(apOld[i]);
+    apOld[i] = 0;
+    i++;
+  }
+
   /*
   ** Put the new pages in accending order.  This helps to
   ** keep entries in the disk file in order so that a scan
@@ -3949,95 +3927,6 @@ static int balance_nonroot(MemPage *pPage){
     nNew>=4 ? pgnoNew[3] : 0, nNew>=4 ? szNew[3] : 0,
     nNew>=5 ? pgnoNew[4] : 0, nNew>=5 ? szNew[4] : 0));
 
-  /* If there are other cursors that refer to one of the pages involved
-  ** in the balancing, then adjust these cursors so that they still
-  ** point to the same cells.
-  */
-  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
-    int nCellCnt = 0;
-    int iCell = -1;
-    Pgno pgno = pCur->pPage->pgno;
-
-    /* If the cursor is not valid, do not do anything with it. */
-    if( !pCur->isValid ) continue;
-
-    /* If the cursor pointed to one of the cells moved around during the
-    ** balancing, then set variable iCell to the index of the cell in apCell.
-    ** This is used by the block below to figure out where the cell was
-    ** moved to, and adjust the cursor appropriately.
-    **
-    ** If the cursor points to the parent page, but the cell was not involved
-    ** in the balance, then declare the cache of the cell-parse invalid, as a
-    ** defragmentation may of occured during  the balance. Also, if the index
-    ** of the cell is greater than that of the divider cells, then it may
-    ** need to be adjusted (in case there are now more or less divider cells
-    ** than there were before the balancing).
-    */
-    for(i=0; iCell<0 && i<nOld; i++){
-      if( pgno==apCopy[i]->pgno ){
-        iCell = nCellCnt + pCur->idx;
-        break;
-      }
-      nCellCnt += (apCopy[i]->nCell + apCopy[i]->nOverflow) + (leafData?0:1);
-    }
-    if( pgno==pParent->pgno ){
-      assert( !leafData );
-      assert( iCell==-1 );
-      if( pCur->idx>=nxDiv && pCur->idx<(nxDiv+nOld-1) ){
-        for(i=0; i<=(pCur->idx-nxDiv); i++){
-          iCell += (apCopy[i]->nCell + apCopy[i]->nOverflow + 1);
-        }
-      }
-      if( pCur->idx>=(nxDiv+nOld-1) ){
-        TRACE(("BALANCE: Cursor %p migrates from %d,%d to %d,%d\n", 
-            pCur, pgno, pCur->idx, pgno, pCur->idx+(nNew-nOld)));
-        pCur->idx += (nNew-nOld);
-      }
-      pCur->info.nSize = 0;
-    }
-
-    /* If iCell is greater than or equal to zero, then pCur points at a
-    ** cell that was moved around during the balance. Figure out where
-    ** the cell was moved to and adjust pCur to match.
-    */
-    if( iCell>=0 ){
-      int idxNew;
-      Pgno pgnoNew;
-      int x = 0;
-
-      assert( iCell<nCell );
-      while( cntNew[x]<=iCell ) x++;
-      if( x>0 && !leafData && cntNew[x-1]==iCell ){
-        /* The cell that pCur points to is a divider cell in pParent. */
-        pgnoNew = pParent->pgno;
-        idxNew = nxDiv + x-1;
-      }else{
-        /* The cell that pCur points to is on page apNew[x]. */
-        idxNew = iCell-(x>0?cntNew[x-1]:0)-((leafData||x==0)?0:1);
-        pgnoNew = apNew[x]->pgno;
-      }
-
-      TRACE(("BALANCE: Cursor %p migrates from %d,%d to %d,%d\n", 
-          pCur, pgno, pCur->idx, pgnoNew, idxNew));
-
-      pCur->idx = idxNew;
-      releasePage(pCur->pPage);
-      rc = getPage(pBt, pgnoNew, &pCur->pPage);
-      assert( rc==SQLITE_OK );
-      assert( pCur->pPage->isInit );
-      pCur->info.nSize = 0;
-    }
-  }
-
-  /* Free any old pages that were not reused as new pages.
-  */
-  for(i=nNew; i<nOld; i++){
-    rc = freePage(apOld[i]);
-    if( rc ) goto balance_cleanup;
-    releasePage(apOld[i]);
-    apOld[i] = 0;
-  }
-
   /*
   ** Evenly distribute the data in apCell[] across the new pages.
   ** Insert divider cells into pParent as necessary.
@@ -4181,7 +4070,6 @@ static int balance_shallower(MemPage *pPage){
         /* The child information will fit on the root page, so do the
         ** copy */
         int i;
-        BtCursor *pCur;
         zeroPage(pPage, pChild->aData[0]);
         for(i=0; i<pChild->nCell; i++){
           apCell[i] = findCell(pChild,i);
@@ -4190,26 +4078,12 @@ static int balance_shallower(MemPage *pPage){
         assemblePage(pPage, pChild->nCell, apCell, szCell);
         freePage(pChild);
         TRACE(("BALANCE: child %d transfer to page 1\n", pChild->pgno));
-        /* If there were cursors pointing at this page, point them at the 
-        ** new page instead. Decrement the reference count for the old 
-        ** page and increment it for the new one.
-        */
-        for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
-          if( pCur->pPage==pChild ){
-            TRACE(("BALANCE: Cursor %p migrates from %d,%d to %d,%d\n", 
-                pCur, pPage->pgno, pCur->idx, pPage->pgno, pCur->idx));
-            releasePage(pCur->pPage);
-            rc = getPage(pBt, 1,  &pCur->pPage);
-            assert( rc==SQLITE_OK );
-          }
-        }
       }else{
         /* The child has more information that will fit on the root.
         ** The tree is already balanced.  Do nothing. */
         TRACE(("BALANCE: child %d will not fit on page 1\n", pChild->pgno));
       }
     }else{
-      BtCursor *pCur;
       memcpy(pPage->aData, pChild->aData, pPage->pBt->usableSize);
       pPage->isInit = 0;
       pPage->pParent = 0;
@@ -4218,15 +4092,6 @@ static int balance_shallower(MemPage *pPage){
       freePage(pChild);
       TRACE(("BALANCE: transfer child %d into root %d\n",
               pChild->pgno, pPage->pgno));
-      for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
-        if( pCur->pPage==pChild ){
-          TRACE(("BALANCE: Cursor %p migrates from %d,%d to %d,%d\n", 
-              pCur, pChild->pgno, pCur->idx, pPage->pgno, pCur->idx));
-          releasePage(pCur->pPage);
-          rc = getPage(pBt, pPage->pgno,  &pCur->pPage);
-          assert( rc==SQLITE_OK );
-        }
-      }
     }
     rc = reparentChildPages(pPage);
     if( rc!=SQLITE_OK ) goto end_shallow_balance;
@@ -4257,7 +4122,6 @@ static int balance_deeper(MemPage *pPage){
   u8 *cdata;          /* Content of the child page */
   int hdr;            /* Offset to page header in parent */
   int brk;            /* Offset to content of first cell in parent */
-  BtCursor *pCur;
 
   assert( pPage->pParent==0 );
   assert( pPage->nOverflow>0 );
@@ -4284,21 +4148,6 @@ static int balance_deeper(MemPage *pPage){
   zeroPage(pPage, pChild->aData[0] & ~PTF_LEAF);
   put4byte(&pPage->aData[pPage->hdrOffset+8], pgnoChild);
   TRACE(("BALANCE: copy root %d into %d\n", pPage->pgno, pChild->pgno));
-
-  /* If there were cursors pointing at this page, point them at the new
-  ** page instead. Decrement the reference count for the old page and
-  ** increment it for the new one.
-  */
-  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
-    if( pCur->pPage==pPage ){
-      TRACE(("BALANCE: Cursor %p migrates from %d,%d to %d,%d\n", 
-          pCur, pPage->pgno, pCur->idx, pChild->pgno, pCur->idx));
-      releasePage(pCur->pPage);
-      rc = getPage(pBt, pChild->pgno,  &pCur->pPage);
-      assert( rc==SQLITE_OK );
-    }
-  }
-
   rc = balance_nonroot(pChild);
   releasePage(pChild);
   return rc;
@@ -4331,8 +4180,24 @@ static int balance(MemPage *pPage){
 ** wrFlag==0 then this routine returns SQLITE_LOCKED.  If all
 ** cursors that point to pgnoRoot 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 moves
+** all cursors other than pExclude so that they are pointing to the 
+** first Cell on root page.  This is necessary because an insert 
+** or delete might change the number of cells on a page or delete
+** a page entirely and we do not want to leave any cursors 
+** pointing to non-existant pages or cells.
 */
 static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){
+  BtCursor *p;
+  for(p=pBt->pCursor; p; p=p->pNext){
+    if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue;
+    if( p->wrFlag==0 ) return SQLITE_LOCKED;
+    if( p->pPage->pgno!=p->pgnoRoot ){
+      moveToRoot(p);
+    }
+  }
   return SQLITE_OK;
 }
 
@@ -4357,7 +4222,6 @@ int sqlite3BtreeInsert(
   Btree *pBt = pCur->pBt;
   unsigned char *oldCell;
   unsigned char *newCell = 0;
-  BtCursor *pCur2;
 
   if( pCur->status ){
     return pCur->status;  /* A rollback destroyed this cursor */
@@ -4409,30 +4273,13 @@ int sqlite3BtreeInsert(
     assert( pPage->leaf );
   }
   rc = insertCell(pPage, pCur->idx, newCell, szNew, 0);
-  pCur->isValid = 1;
-
-  /* If there are other cursors pointing at this page with a BtCursor.idx
-  ** field greater than or equal to 'i', then the cell they refer to
-  ** has been modified or moved within the page. Fix the cursor.
-  */
-  for(pCur2=pPage->pBt->pCursor; pCur2; pCur2 = pCur2->pNext){
-    if( pCur2->pPage==pPage ){
-      if( pCur2->idx>=pCur->idx && pCur!=pCur2 && loc!=0 ){
-       /* The cell pointed to by pCur2 was shifted one to the right on it's
-       ** page by this Insert(). 
-        */
-        TRACE(("INSERT: Cursor %p migrates from %d,%d to %d,%d\n", 
-            pCur2, pPage->pgno, pCur2->idx, pPage->pgno, pCur2->idx+1));
-        pCur2->idx++;
-      }
-      pCur2->info.nSize = 0;
-    }
-  }
-
   if( rc!=SQLITE_OK ) goto end_insert;
   rc = balance(pPage);
   /* sqlite3BtreePageDump(pCur->pBt, pCur->pgnoRoot, 1); */
   /* fflush(stdout); */
+  if( rc==SQLITE_OK ){
+    moveToRoot(pCur);
+  }
 end_insert:
   sqliteFree(newCell);
   return rc;
@@ -4448,8 +4295,6 @@ int sqlite3BtreeDelete(BtCursor *pCur){
   int rc;
   Pgno pgnoChild = 0;
   Btree *pBt = pCur->pBt;
-  int idx;                /* Index of the cell to delete */
-  BtCursor *pCur2;        /* Iterator variable for the pBt.pCursor link-list */
 
   assert( pPage->isInit );
   if( pCur->status ){
@@ -4472,50 +4317,11 @@ int sqlite3BtreeDelete(BtCursor *pCur){
   rc = sqlite3pager_write(pPage->aData);
   if( rc ) return rc;
 
-  /* Set index to the index in pPage that contains the cell to delete. Also
-  ** increment the reference count for pPage. This allows us to move the
-  ** cursor pCur before the delete takes place.
-  */
-  idx = pCur->idx;
-  rc = getPage(pBt, pPage->pgno, &pPage);
-  if( rc ) return rc;
-  assert( pPage==pCur->pPage );
-
-  /* If there are any cursors that point to the cell being deleted, 
-  ** move them to the next or previous entry in the table. It is preferable
-  ** to move the cursor to the 'next' location, rather than the 'previous'
-  ** one, as most table scans are done in the forward direction (also, code
-  ** below depends on this). If neither entry exists, declare the cursor
-  ** invalid.
-  */ 
-  for(pCur2=pBt->pCursor; pCur2; pCur2 = pCur2->pNext){
-    if( pCur2->pPage==pPage && pCur2->idx==idx && pCur2->isValid ){
-      int res;
-      pCur2->delShift = 0;
-      rc = sqlite3BtreeNext(pCur2, &res);
-      if( rc ) goto delete_out;
-      if( res ){
-        /* If the next tree entry cannot be found, then the cursor must
-        ** already point to the last table entry. So point it to the
-        ** second last by calling BtreeLast(), BtreePrevious().
-        */
-        rc = sqlite3BtreeLast(pCur2, &res);
-        if( rc ) goto delete_out;
-        assert( res==0 );
-        rc = sqlite3BtreePrevious(pCur2, &res);
-        if( rc ) goto delete_out;
-        pCur2->delShift = -1;
-      }else{
-        pCur2->delShift = 1;
-      }
-    }
-  }
-
   /* Locate the cell within it's page and leave pCell pointing to the
   ** data. The clearCell() call frees any overflow pages associated with the
   ** cell. The cell itself is still intact.
   */
-  pCell = findCell(pPage, idx);
+  pCell = findCell(pPage, pCur->idx);
   if( !pPage->leaf ){
     pgnoChild = get4byte(pCell);
   }
@@ -4527,120 +4333,48 @@ int sqlite3BtreeDelete(BtCursor *pCur){
     ** do something we will leave a hole on an internal page.
     ** We have to fill the hole by moving in a cell from a leaf.  The
     ** next Cell after the one to be deleted is guaranteed to exist and
-    ** to be a leaf so we can use it. Conveniantly, pCur now points
-    ** at this cell (because it was advanced above).
+    ** to be a leaf so we can use it.
     */
     BtCursor leafCur;
     unsigned char *pNext;
     int szNext;
+    int notUsed;
     unsigned char *tempCell;
     assert( !pPage->leafData );
-
-    /* Make a copy of *pCur in leafCur. leafCur now points to the cell 
-    ** that will be moved into the space left by the cell being deleted.
-    */
-    assert( pCur->delShift==1 );
-    assert( pCur->isValid );
     getTempCursor(pCur, &leafCur);
+    rc = sqlite3BtreeNext(&leafCur, &notUsed);
     if( rc!=SQLITE_OK ){
       if( rc!=SQLITE_NOMEM ){
         rc = SQLITE_CORRUPT;  /* bkpt-CORRUPT */
       }
-      goto delete_out;
+      return rc;
     }
     rc = sqlite3pager_write(leafCur.pPage->aData);
-    if( rc ) goto delete_out;
-    TRACE(("DELETE: table=%d delete internal from %d,%d replace "
-        "from leaf %d,%d\n", pCur->pgnoRoot, pPage->pgno, idx, 
-        leafCur.pPage->pgno, leafCur.idx));
-
-    /* Drop the cell from the internal page. Make a copy of the cell from
-    ** the leaf page into memory obtained from malloc(). Insert it into
-    ** the internal page, at the position vacated by the delete. There
-    ** are now two copies of the leaf-cell in the tree.
-    */
-    dropCell(pPage, idx, cellSizePtr(pPage, pCell));
+    if( rc ) return rc;
+    TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n",
+       pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno));
+    dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell));
     pNext = findCell(leafCur.pPage, leafCur.idx);
     szNext = cellSizePtr(leafCur.pPage, pNext);
     assert( MX_CELL_SIZE(pBt)>=szNext+4 );
     tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
-    if( tempCell==0 ){
-       rc = SQLITE_NOMEM;
-       goto delete_out;
-    }
-    rc = insertCell(pPage, idx, pNext-4, szNext+4, tempCell);
-    if( rc!=SQLITE_OK ) goto delete_out;
-    put4byte(findOverflowCell(pPage, idx), pgnoChild);
-    pPage->idxShift = 0;
-
-    /* If there are any cursors that point to the leaf-cell, move them
-    ** so that they point at internal cell. This is easiest done by
-    ** calling BtreePrevious().
-    **
-    ** Also, any cursors that point to the internal page have their
-    ** cached parses invalidated, as the insertCell() above may have 
-    ** caused a defragmation.
-    */
-    for(pCur2=pBt->pCursor; pCur2; pCur2 = pCur2->pNext){
-      if( pCur2->pPage==leafCur.pPage && pCur2->idx==leafCur.idx ){
-        int res;
-        int delShiftSave = pCur2->delShift; 
-        assert( leafCur.idx==0 );
-        pCur2->delShift = 0;
-        rc = sqlite3BtreePrevious(pCur2, &res);
-        if( rc ) goto delete_out;
-        assert( res==0 );
-        assert( pCur2->pPage==pPage );
-        assert( pCur2->idx==idx );
-        pCur2->delShift = delShiftSave;
-      }
-      if( pCur2->pPage==pPage ){
-        pCur2->info.nSize = 0;
-      }
-    }
-
-    /* Balance the internal page. Free the memory allocated for the 
-    ** copy of the leaf cell. Then delete the cell from the leaf page.
-    */
+    if( tempCell==0 ) return SQLITE_NOMEM;
+    rc = insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell);
+    if( rc!=SQLITE_OK ) return rc;
+    put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild);
     rc = balance(pPage);
     sqliteFree(tempCell);
-    if( rc ) goto delete_out;
+    if( rc ) return rc;
     dropCell(leafCur.pPage, leafCur.idx, szNext);
-
-    for(pCur2=pBt->pCursor; pCur2; pCur2 = pCur2->pNext){
-      if( pCur2->pPage==leafCur.pPage && pCur2->idx>leafCur.idx ){
-        TRACE(("DELETE: Cursor %p migrates from %d,%d to %d,%d\n", pCur2, 
-            leafCur.pPage->pgno,pCur2->idx,leafCur.pPage->pgno, pCur2->idx-1));
-        pCur2->idx--;
-        pCur2->info.nSize = 0;
-      }
-    }
-
     rc = balance(leafCur.pPage);
     releaseTempCursor(&leafCur);
   }else{
-    TRACE(("DELETE: table=%d delete %d from leaf %d\n",
-       pCur->pgnoRoot, idx, pPage->pgno));
-    dropCell(pPage, idx, cellSizePtr(pPage, pCell));
-
-    /* If there were cursors pointing to cells on pPage with index values
-    ** greater than idx, decrement the index values now.
-    */
-    for(pCur2=pBt->pCursor; pCur2; pCur2 = pCur2->pNext){
-      assert( !pCur2->isValid || pCur2->pPage!=pPage || pCur2->idx!=idx );
-      if( pCur2->pPage==pPage && pCur2->idx>idx ){
-        TRACE(("DELETE: Cursor %p migrates from %d,%d to %d,%d\n", 
-            pCur2, pPage->pgno, pCur2->idx, pPage->pgno, pCur2->idx-1));
-        pCur2->idx--;
-        pCur2->info.nSize = 0;
-      }
-    }
-
+    TRACE(("DELETE: table=%d delete from leaf %d\n",
+       pCur->pgnoRoot, pPage->pgno));
+    dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell));
     rc = balance(pPage);
   }
-
-delete_out:
-  releasePage(pPage);
+  moveToRoot(pCur);
   return rc;
 }
 
index 43ee228424ab0cdc3f0ddbf25a86219d4d41c7e3..4887d69848d6e41c422f6cec776d42759457f796 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.89 2004/11/16 15:50:20 danielk1977 Exp $
+** $Id: delete.c,v 1.90 2004/11/22 10:02:10 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -64,6 +64,7 @@ void sqlite3OpenTableForReading(
   sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol);
 }
 
+
 /*
 ** Process a DELETE FROM statement.
 */
@@ -75,7 +76,7 @@ void sqlite3DeleteFrom(
   Vdbe *v;               /* The virtual database engine */
   Table *pTab;           /* The table from which records will be deleted */
   const char *zDb;       /* Name of database holding pTab */
-  int addr = 0;          /* A couple addresses of generated code */
+  int end, addr = 0;     /* A couple addresses of generated code */
   int i;                 /* Loop counter */
   WhereInfo *pWInfo;     /* Information about the WHERE clause */
   Index *pIdx;           /* For looping over indices of the table */
@@ -149,15 +150,10 @@ void sqlite3DeleteFrom(
     oldIdx = pParse->nTab++;
   }
 
-  /* Resolve the column names in all the expressions. Allocate cursors
-  ** for the table and indices first, in case an expression needs to use
-  ** a cursor (e.g. an IN() expression).
+  /* Resolve the column names in all the expressions.
   */
   assert( pTabList->nSrc==1 );
   iCur = pTabList->a[0].iCursor = pParse->nTab++;
-  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
-    pParse->nTab++;
-  }
   if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){
     goto delete_from_cleanup;
   }
@@ -231,6 +227,22 @@ void sqlite3DeleteFrom(
       }
     }
 
+    /* Begin the database scan
+    */
+    pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
+    if( pWInfo==0 ) goto delete_from_cleanup;
+
+    /* Remember the key of every item to be deleted.
+    */
+    sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0);
+    if( db->flags & SQLITE_CountRows ){
+      sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
+    }
+
+    /* End the database scan loop.
+    */
+    sqlite3WhereEnd(pWInfo);
+
     /* Open the pseudo-table used to store OLD if there are triggers.
     */
     if( row_triggers_exist ){
@@ -238,49 +250,80 @@ void sqlite3DeleteFrom(
       sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
     }
 
-    /* Open cursors for the table and indices we are deleting from. */
-    if( !isView ){
-      sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
-    }
-
-    /* Begin the database scan
+    /* Delete every item whose key was written to the list during the
+    ** database scan.  We have to delete items after the scan is complete
+    ** because deleting an item can change the scan order.
     */
-    pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, isView?0:iCur);
-    if( pWInfo==0 ) goto delete_from_cleanup;
-    addr = pWInfo->iContinue;
+    sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
+    end = sqlite3VdbeMakeLabel(v);
 
-    /* If row-triggers exist, copy the record being deleted into the
-    ** oldIdx psuedo-table. Then invoke the BEFORE triggers.
+    /* This is the beginning of the delete loop when there are
+    ** row triggers.
     */
     if( row_triggers_exist ){
+      addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
+      sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
+      if( !isView ){
+        sqlite3OpenTableForReading(v, iCur, pTab);
+      }
+      sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
       sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
       sqlite3VdbeAddOp(v, OP_RowData, iCur, 0);
       sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
+      if( !isView ){
+        sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
+      }
+
       (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, 
           oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
          addr);
     }
 
-    /* Delete the row. Increment the callback value if the count-rows flag 
-    ** is set. 
-    */
-    if( db->flags & SQLITE_CountRows ){
-      sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
+    if( !isView ){
+      /* Open cursors for the table we are deleting from and all its
+      ** indices.  If there are row triggers, this happens inside the
+      ** OP_ListRead loop because the cursor have to all be closed
+      ** before the trigger fires.  If there are no row triggers, the
+      ** cursors are opened only once on the outside the loop.
+      */
+      sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
+
+      /* This is the beginning of the delete loop when there are no
+      ** row triggers */
+      if( !row_triggers_exist ){ 
+        addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end);
+      }
+
+      /* Delete the row */
+      sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
     }
-    sqlite3VdbeAddOp(v, OP_Recno, iCur, 0);
-    sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
 
-    /* Code the AFTER triggers.  */
+    /* If there are row triggers, close all cursors then invoke
+    ** the AFTER triggers
+    */
     if( row_triggers_exist ){
+      if( !isView ){
+        for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
+          sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
+        }
+        sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
+      }
       (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, 
           oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
          addr);
     }
 
-    /* End the database scan loop and close indices. */
-    sqlite3WhereEnd(pWInfo);
-    for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
-      sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
+    /* End of the delete loop */
+    sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
+    sqlite3VdbeResolveLabel(v, end);
+    sqlite3VdbeAddOp(v, OP_ListReset, 0, 0);
+
+    /* Close the cursors after the loop if there are no row triggers */
+    if( !row_triggers_exist ){
+      for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
+        sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
+      }
+      sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
     }
   }
 
index 00ffa4060736e09d3b91d51445addbfb072bf018..412ee8eb6f08b0f7b39125043cbfd69af0489e1a 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.214 2004/11/16 15:50:20 danielk1977 Exp $
+** $Id: select.c,v 1.215 2004/11/22 10:02:11 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -2523,7 +2523,7 @@ int sqlite3Select(
   /* Begin the database scan
   */
   pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 
-                            pGroupBy ? 0 : &pOrderBy, -1);
+                            pGroupBy ? 0 : &pOrderBy);
   if( pWInfo==0 ) goto select_end;
 
   /* Use the standard inner loop if we are not dealing with
index 39ae7ae615bf470bdb1584e4f05400b2bcedfe69..9be16bc95676b2c3677d7a96d9b7f12e0344a688 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.341 2004/11/20 19:18:01 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.342 2004/11/22 10:02:11 danielk1977 Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1314,10 +1314,9 @@ void sqlite3SelectUnbind(Select*);
 Table *sqlite3SrcListLookup(Parse*, SrcList*);
 int sqlite3IsReadOnly(Parse*, Table*, int);
 void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*);
-void sqlite3OpenTable(Vdbe*, int iCur, Table*, int);
 void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
 void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
-WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**, int);
+WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**);
 void sqlite3WhereEnd(WhereInfo*);
 void sqlite3ExprCode(Parse*, Expr*);
 int sqlite3ExprCodeExprList(Parse*, ExprList*);
index b56574cb6c1260485ef1c423f5d262d0b4d7a57b..501ca6c3eb385b2f1cadd70a2ef0fb05957cfbf6 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.95 2004/11/16 15:50:20 danielk1977 Exp $
+** $Id: update.c,v 1.96 2004/11/22 10:02:11 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -235,7 +235,7 @@ void sqlite3Update(
 
   /* Begin the database scan
   */
-  pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0, -1);
+  pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
   if( pWInfo==0 ) goto update_cleanup;
 
   /* Remember the index of every item to be updated.
index f1a9a0c0b237fd54e94296a84a95156a5f0f2e21..c3f8082fc2be9e496dea5cf4b9a8f10a718a95dc 100644 (file)
@@ -12,7 +12,7 @@
 ** This module contains C code that generates VDBE code used to process
 ** the WHERE clause of SQL statements.
 **
-** $Id: where.c,v 1.117 2004/11/16 15:50:20 danielk1977 Exp $
+** $Id: where.c,v 1.118 2004/11/22 10:02:20 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -481,8 +481,7 @@ WhereInfo *sqlite3WhereBegin(
   SrcList *pTabList,    /* A list of all tables to be scanned */
   Expr *pWhere,         /* The WHERE clause */
   int pushKey,          /* If TRUE, leave the table key on the stack */
-  ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */
-  int iTabCur           /* Cursor for pTabList->aSrc[0] */
+  ExprList **ppOrderBy  /* An ORDER BY clause, or NULL */
 ){
   int i;                     /* Loop counter */
   WhereInfo *pWInfo;         /* Will become the return value of this function */
@@ -778,9 +777,7 @@ WhereInfo *sqlite3WhereBegin(
 
     pTab = pTabList->a[i].pTab;
     if( pTab->isTransient || pTab->pSelect ) continue;
-    if( i>0 || iTabCur<0 ){
-      sqlite3OpenTableForReading(v, pTabList->a[i].iCursor, pTab);
-    }
+    sqlite3OpenTableForReading(v, pTabList->a[i].iCursor, pTab);
     sqlite3CodeVerifySchema(pParse, pTab->iDb);
     if( (pIx = pWInfo->a[i].pIdx)!=0 ){
       sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0);