]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
The btree.c module now passes all the historical regression tests. New tests
authordrh <drh@noemail.net>
Mon, 10 May 2004 16:18:47 +0000 (16:18 +0000)
committerdrh <drh@noemail.net>
Mon, 10 May 2004 16:18:47 +0000 (16:18 +0000)
for new functionality still need to be added. (CVS 1342)

FossilOrigin-Name: 433ae0d327e5d5b0761e88418ed57fc4cbf4966b

manifest
manifest.uuid
src/btree.c
src/sqlite.h.in
src/test3.c
test/btree2.test

index 31559757339ffbcaa4b5b6481e4e3092289a23f2..3dc04121ff9b023fe158f291aad29de7d55984d1 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sflags\svalues\sto\sthe\sMem\sstructure\sto\saccomodate\sBLOBs\sand\sto\sshow\nthe\srepresentation\sof\sstrings.\s(CVS\s1341)
-D 2004-05-10T12:07:11
+C The\sbtree.c\smodule\snow\spasses\sall\sthe\shistorical\sregression\stests.\s\sNew\stests\nfor\snew\sfunctionality\sstill\sneed\sto\sbe\sadded.\s(CVS\s1342)
+D 2004-05-10T16:18:48
 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -23,7 +23,7 @@ F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f
 F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
 F src/attach.c fa9a58234406d84eeb900517d0c0adc4b2da051a
 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
-F src/btree.c b5950a1fece49f4a57f49a88b80610aae120bf16
+F src/btree.c 1b29a6915b2ac5d5c9919e1a461a09bc1e7b8a76
 F src/btree.h 7c3939a2e5f782c1ebac3bf43c02a16febad6df1
 F src/btree_rb.c 9d7973e266ee6f9c61ce592f68742ce9cd5b10e5
 F src/build.c 8d9965b3ce5dcc1bd4dac60bd0f14524fea269cb
@@ -48,13 +48,13 @@ F src/printf.c 8aa5d88509f46f064f57d0a8419e7b5f3b9fd559
 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
 F src/select.c 9290439282fdc787fdf34d8600dec3a360275c92
 F src/shell.c 255b8b9023cb5274f56d87df437e8ce6ef810b91
-F src/sqlite.h.in cfdb920ed7b68692720263f8b662f276fe15f33c
+F src/sqlite.h.in 799c5e726296ec7bc20e6407cdf4df0e0bc00c0c
 F src/sqliteInt.h 3151a1c14fc07f96169e904913d28c7ab173d8ca
 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
 F src/tclsqlite.c a38bf2263a097fcc9603e818c291151de1782c11
 F src/test1.c 79956f70dddd1a28f8577bbd61c8cf28e5875eb8
 F src/test2.c 6195a1ca2c8d0d2d93644e86da3289b403486872
-F src/test3.c d6d9d943de0926688fed4c4f5f5b345afda1ba73
+F src/test3.c bcc9a49e8d2cb7864efb964974e1807f3e0c30c4
 F src/test4.c b3fab9aea7a8940a8a7386ce1c7e2157b09bd296
 F src/test5.c eb39aac8fed61bd930b92613cd705c145244074a
 F src/tokenize.c e7536dd31205d5afb76c1bdc832dea009c7a3847
@@ -76,7 +76,7 @@ F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81
 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
 F test/bind.test 56a57043b42c4664ca705f6050e56717a8a6699a
 F test/btree.test ed5781db83b6c1de02e62781d44915a9abe3450a
-F test/btree2.test aed860c48f873f1678a94786bc1e6eab09a0419b
+F test/btree2.test aa4a6d05b1ea90b1acaf83ba89039dd302a88635
 F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4
 F test/capi2.test ec96e0e235d87b53cbaef3d8e3e0f8ccf32c71ca
 F test/conflict.test 0911bb2f079046914a6e9c3341b36658c4e2103e
@@ -187,7 +187,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P ac46bd686d2211813d254af578fe4e211162bc4b
-R 4a9fc99f56e83c67635aeaf2f3df4688
+P 3af283f483f75795d5b03dc8fd886aaf326d50b7
+R 6546c34bdaf9d2a72d3829b11104409d
 U drh
-Z 2e2c13a294ecee6121fff95c45eff825
+Z 3dbc1d278bc85c72de8f6c60be466152
index 50437f9ad206238492407e66ceda988139420fce..a907a7e232237c84755d6f15da09ec758fbb51a5 100644 (file)
@@ -1 +1 @@
-3af283f483f75795d5b03dc8fd886aaf326d50b7
\ No newline at end of file
+433ae0d327e5d5b0761e88418ed57fc4cbf4966b
\ No newline at end of file
index c5b270bdd869e03ae75d7a6906057cba6d2553f5..0e65010165e97fa62acea7e22742b53af42b4935 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.121 2004/05/10 10:34:34 danielk1977 Exp $
+** $Id: btree.c,v 1.122 2004/05/10 16:18:48 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -529,6 +529,7 @@ static void defragmentPage(MemPage *pPage){
 static int allocateSpace(MemPage *pPage, int nByte){
   int addr, pc, hdr;
   int size;
+  int nFrag;
   unsigned char *data;
 #ifndef NDEBUG
   int cnt = 0;
@@ -540,7 +541,8 @@ static int allocateSpace(MemPage *pPage, int nByte){
   if( nByte<4 ) nByte = 4;
   if( pPage->nFree<nByte || pPage->isOverfull ) return 0;
   hdr = pPage->hdrOffset;
-  if( data[hdr+5]>=60 ){
+  nFrag = data[hdr+5];
+  if( nFrag>=60 || nFrag>pPage->nFree-nByte ){
     defragmentPage(pPage);
   }
   addr = hdr+1;
@@ -1132,10 +1134,21 @@ 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;
-  rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_rollback(pBt->pPager);
+  if( pBt->readOnly ){
+    rc = SQLITE_OK;
+  }else{
+    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
+    ** set correctly. */
+    if( getPage(pBt, 1, &pPage1)==SQLITE_OK ){
+      releasePage(pPage1);
+    }
+  }
   invalidateCursors(pBt);
   unlockBtreeIfUnused(pBt);
   return rc;
@@ -1281,6 +1294,10 @@ int sqlite3BtreeCursor(
     goto create_cursor_exception;
   }
   pCur->pgnoRoot = (Pgno)iTable;
+  if( iTable==1 && sqlite3pager_pagecount(pBt->pPager)==0 ){
+    rc = SQLITE_EMPTY;
+    goto create_cursor_exception;
+  }
   rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->pPage, 0);
   if( rc!=SQLITE_OK ){
     goto create_cursor_exception;
@@ -2434,8 +2451,10 @@ static void dropCell(MemPage *pPage, int idx, int sz){
 ** content of the cell.
 **
 ** If the cell content will fit on the page, then put it there.  If it
-** will not fit, then just make pPage->aCell[i] point to the content
-** and set pPage->isOverfull.  
+** will not fit and pTemp is not NULL, then make a copy of the content
+** into pTemp, set pPage->aCell[i] point to pTemp, and set pPage->isOverfull.
+** If the content will not fit and pTemp is NULL, then make pPage->aCell[i]
+** point to pCell and set pPage->isOverfull.
 **
 ** Try to maintain the integrity of the linked list of cells.  But if
 ** the cell being inserted does not fit on the page, this will not be
@@ -2443,7 +2462,13 @@ static void dropCell(MemPage *pPage, int idx, int sz){
 ** pPage->aCell[] and set the pPage->needRelink flag so that we will
 ** know to rebuild the linked list later.
 */
-static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){
+static void insertCell(
+  MemPage *pPage,   /* Page into which we are copying */
+  int i,            /* Which cell on pPage to insert after */
+  u8 *pCell,        /* Text of the new cell to insert */
+  int sz,           /* Bytes of data in pCell */
+  u8 *pTemp         /* Temp storage space for pCell, if needed */
+){
   int idx, j;
   assert( i>=0 && i<=pPage->nCell );
   assert( sz==cellSize(pPage, pCell) );
@@ -2456,7 +2481,12 @@ static void insertCell(MemPage *pPage, int i, unsigned char *pCell, int sz){
   pPage->nCell++;
   if( idx<=0 ){
     pPage->isOverfull = 1;
-    pPage->aCell[i] = pCell;
+    if( pTemp ){
+      memcpy(pTemp, pCell, sz);
+    }else{
+      pTemp = pCell;
+    }
+    pPage->aCell[i] = pTemp;
   }else{
     u8 *data = pPage->aData;
     memcpy(&data[idx], pCell, sz);
@@ -2619,6 +2649,7 @@ static int balance(MemPage *pPage){
   int idxDiv[NB];              /* Indices of divider cells in pParent */
   u8 *apDiv[NB];               /* Divider cells in pParent */
   u8 aTemp[NB][MX_CELL_SIZE];  /* Temporary holding area for apDiv[] */
+  u8 aInsBuf[NB][MX_CELL_SIZE];/* Space to hold dividers cells during insert */
   int cntNew[NB+1];            /* Index in aCell[] of cell after i-th page */
   int szNew[NB+1];             /* Combined size of cells place on i-th page */
   u8 *apCell[(MX_CELL+2)*NB];  /* All cells from pages being balanced */
@@ -2678,7 +2709,7 @@ static int balance(MemPage *pPage){
             resizeCellArray(pPage, pChild->nCell);
             for(i=0; i<pChild->nCell; i++){
               insertCell(pPage, i, pChild->aCell[i], 
-                        cellSize(pChild, pChild->aCell[i]));
+                        cellSize(pChild, pChild->aCell[i]), 0);
             }
             freePage(pChild);
             TRACE(("BALANCE: child %d transfer to page 1\n", pChild->pgno));
@@ -2955,6 +2986,15 @@ static int balance(MemPage *pPage){
       apNew[minI] = pT;
     }
   }
+  TRACE(("BALANCE: old: %d %d %d  new: %d %d %d %d\n",
+    pgnoOld[0], 
+    nOld>=2 ? pgnoOld[1] : 0,
+    nOld>=3 ? pgnoOld[2] : 0,
+    pgnoNew[0],
+    nNew>=2 ? pgnoNew[1] : 0,
+    nNew>=3 ? pgnoNew[2] : 0,
+    nNew>=4 ? pgnoNew[3] : 0));
+
 
   /*
   ** Evenly distribute the data in apCell[] across the new pages.
@@ -2967,7 +3007,7 @@ static int balance(MemPage *pPage){
     resizeCellArray(pNew, cntNew[i] - j);
     while( j<cntNew[i] ){
       assert( pNew->nFree>=szCell[j] );
-      insertCell(pNew, pNew->nCell, apCell[j], szCell[j]);
+      insertCell(pNew, pNew->nCell, apCell[j], szCell[j], 0);
       j++;
     }
     assert( pNew->nCell>0 );
@@ -2975,12 +3015,15 @@ static int balance(MemPage *pPage){
     relinkCellList(pNew);
     if( i<nNew-1 && j<nCell ){
       u8 *pCell = apCell[j];
+      u8 *pTemp;
       if( !pNew->leaf ){
-        memcpy(&pNew->aData[6], &apCell[j][2], 4);
+        memcpy(&pNew->aData[6], pCell+2, 4);
+        pTemp = 0;
       }else{
         pCell -= 4;
+        pTemp = aInsBuf[i];
       }
-      insertCell(pParent, nxDiv, pCell, szCell[j]+leafCorrection);
+      insertCell(pParent, nxDiv, pCell, szCell[j]+leafCorrection, pTemp);
       put4byte(&pParent->aCell[nxDiv][2], pNew->pgno);
       j++;
       nxDiv++;
@@ -3133,7 +3176,7 @@ int sqlite3BtreeInsert(
   }else{
     assert( pPage->leaf );
   }
-  insertCell(pPage, pCur->idx, newCell, szNew);
+  insertCell(pPage, pCur->idx, newCell, szNew, 0);
   rc = balance(pPage);
   /* sqlite3BtreePageDump(pCur->pBt, pCur->pgnoRoot, 1); */
   /* fflush(stdout); */
@@ -3189,7 +3232,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
     unsigned char *pNext;
     int szNext;
     int notUsed;
-    unsigned char tempbuf[4];
+    unsigned char tempCell[MX_CELL_SIZE];
     getTempCursor(pCur, &leafCur);
     rc = sqlite3BtreeNext(&leafCur, &notUsed);
     if( rc!=SQLITE_OK ){
@@ -3203,12 +3246,11 @@ int sqlite3BtreeDelete(BtCursor *pCur){
     dropCell(pPage, pCur->idx, cellSize(pPage, pCell));
     pNext = leafCur.pPage->aCell[leafCur.idx];
     szNext = cellSize(leafCur.pPage, pNext);
-    memcpy(tempbuf, &pNext[-2], 4);
-    put4byte(&pNext[-2], pgnoChild);
-    insertCell(pPage, pCur->idx, &pNext[-4], szNext+4);
+    assert( sizeof(tempCell)>=szNext+4 );
+    insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell);
+    put4byte(pPage->aCell[pCur->idx]+2, pgnoChild);
     rc = balance(pPage);
     if( rc ) return rc;
-    memcpy(&pNext[-2], tempbuf, 4);
     dropCell(leafCur.pPage, leafCur.idx, szNext);
     rc = balance(leafCur.pPage);
     releaseTempCursor(&leafCur);
index 272735d834014b2ccb501bb4f6f607ed6e7d01bd..7b3f32a209bb81039ae31167ce9441726d1ecd56 100644 (file)
@@ -12,7 +12,7 @@
 ** This header file defines the interface that the SQLite library
 ** presents to client programs.
 **
-** @(#) $Id: sqlite.h.in,v 1.62 2004/05/10 10:34:52 danielk1977 Exp $
+** @(#) $Id: sqlite.h.in,v 1.63 2004/05/10 16:18:48 drh Exp $
 */
 #ifndef _SQLITE_H_
 #define _SQLITE_H_
@@ -150,14 +150,14 @@ int sqlite3_exec(
 #define SQLITE_LOCKED       6   /* A table in the database is locked */
 #define SQLITE_NOMEM        7   /* A malloc() failed */
 #define SQLITE_READONLY     8   /* Attempt to write a readonly database */
-#define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite3_interrupt() */
+#define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite3_interrupt()*/
 #define SQLITE_IOERR       10   /* Some kind of disk I/O error occurred */
 #define SQLITE_CORRUPT     11   /* The database disk image is malformed */
 #define SQLITE_NOTFOUND    12   /* (Internal Only) Table or record not found */
 #define SQLITE_FULL        13   /* Insertion failed because database is full */
 #define SQLITE_CANTOPEN    14   /* Unable to open the database file */
 #define SQLITE_PROTOCOL    15   /* Database lock protocol error */
-#define SQLITE_EMPTY       16   /* (Internal Only) Database table is empty */
+#define SQLITE_EMPTY       16   /* Database is empty */
 #define SQLITE_SCHEMA      17   /* The database schema changed */
 #define SQLITE_TOOBIG      18   /* Too much data for one row of a table */
 #define SQLITE_CONSTRAINT  19   /* Abort due to contraint violation */
@@ -921,6 +921,3 @@ double sqlite3_column_float(sqlite3_stmt*,int);
 }  /* End of the 'extern "C"' block */
 #endif
 #endif
-
-
-
index 18e39f6a933c94ece262e49b6422b17c7f7b20ec..fe250eb2ccf219998f1d7389ff532601197e2cf6 100644 (file)
@@ -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.33 2004/05/09 20:40:11 drh Exp $
+** $Id: test3.c,v 1.34 2004/05/10 16:18:48 drh Exp $
 */
 #include "sqliteInt.h"
 #include "pager.h"
@@ -43,6 +43,7 @@ static char *errorName(int rc){
     case SQLITE_FULL:       zName = "SQLITE_FULL";        break;
     case SQLITE_CANTOPEN:   zName = "SQLITE_CANTOPEN";    break;
     case SQLITE_PROTOCOL:   zName = "SQLITE_PROTOCOL";    break;
+    case SQLITE_EMPTY:      zName = "SQLITE_EMPTY";       break;
     default:                zName = "SQLITE_Unknown";     break;
   }
   return zName;
index 9a85e9daffb8b0138de1dcd7d1fb3220f9a0362a..65d32dfc1c60166aba31f39dec637c0adfd87e6a 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this script is btree database backend
 #
-# $Id: btree2.test,v 1.12 2004/05/09 20:40:11 drh Exp $
+# $Id: btree2.test,v 1.13 2004/05/10 16:18:48 drh Exp $
 
 
 set testdir [file dirname $argv0]
@@ -73,7 +73,7 @@ do_test btree2-1.6 {
 #       for foreground and background tables.
 #
 #   2.  The union of the foreground an background tables consists of N entries
-#       where each entry an L-digit key.  (Actually, some keys can be longer 
+#       where each entry has an L-digit key. (Actually, some keys can be longer 
 #       than L characters, but they always start with L digits.)  The keys
 #       cover all integers between 1 and N.  Whenever an entry is added to
 #       the foreground it is removed form the background and vice versa.
@@ -149,10 +149,6 @@ proc check_invariants {} {
       set key [btree_key $::c4]
       if {[scan $key %d k]<1} {set k 0}
       if {$k!=$i} {
-        # puts "MISSING $i"
-        # puts {Page 3:}; btree_page_dump $::b 3
-        # puts {Page 4:}; btree_page_dump $::b 4
-        # exit
         return "Key $i is missing from both foreground and background"
       }
       set data [btree_data $::c4]
@@ -189,6 +185,32 @@ proc check_invariants {} {
   }
 }
 
+# Look at all elements in both the foreground and background tables.
+# Make sure the key is always the same as the prefix of the data.
+#
+# This routine was used for hunting bugs.  It is not a part of standard
+# tests.
+#
+proc check_data {n key} {
+  global c3 c4
+  incr n -1
+  foreach c [list $c3 $c4] {
+    btree_first $c  ;# move_to $c $key
+    set cnt 0
+    while {![btree_eof $c]} {
+      set key [btree_key $c]
+      set data [btree_data $c]
+      if {[string range $key 0 $n] ne [string range $data 0 $n]} {
+        puts "key=[list $key] data=[list $data] n=$n"
+        puts "cursor info = [btree_cursor_info $c]"
+        btree_page_dump $::b [lindex [btree_cursor_info $c] 0]
+        exit
+      }
+      btree_next $c
+    }
+  }
+}
+
 # Make random changes to the database such that each change preserves
 # the invariants.  The number of changes is $n*N where N is the parameter
 # from the descriptor table.  Each changes begins with a random key.
@@ -285,6 +307,7 @@ proc random_changes {n I K D} {
     }
   }
 }
+set btree_trace 0
 
 # Repeat this test sequence on database of various sizes
 #
@@ -397,7 +420,6 @@ foreach {N L} {
     set ::c4 [btree_cursor $::b 4 1]
     set ::c5 [btree_cursor $::b 5 1]
     set ::c6 [btree_cursor $::b 6 1]
-#if {$testid=="btree2-3.8.4"} {set btree_trace 1}
     do_test $testid.5 [subst {
       random_changes $n $I $K $D
     }] {}