diff --git a/manifest b/manifest index 3155975733..3dc04121ff 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 50437f9ad2..a907a7e232 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3af283f483f75795d5b03dc8fd886aaf326d50b7 \ No newline at end of file +433ae0d327e5d5b0761e88418ed57fc4cbf4966b \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index c5b270bdd8..0e65010165 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.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->nFreeisOverfull ) 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; inCell; 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( jnFree>=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( ileaf ){ - 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, ¬Used); 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); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 272735d834..7b3f32a209 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -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 - - - diff --git a/src/test3.c b/src/test3.c index 18e39f6a93..fe250eb2cc 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.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; diff --git a/test/btree2.test b/test/btree2.test index 9a85e9daff..65d32dfc1c 100644 --- a/test/btree2.test +++ b/test/btree2.test @@ -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 }] {}