]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
More tests and bug fixes in btree.c (CVS 229)
authordrh <drh@noemail.net>
Mon, 25 Jun 2001 02:11:07 +0000 (02:11 +0000)
committerdrh <drh@noemail.net>
Mon, 25 Jun 2001 02:11:07 +0000 (02:11 +0000)
FossilOrigin-Name: 6b9b298b2846146b95d7df7f423867976bafa390

manifest
manifest.uuid
src/btree.c
src/btree.h
src/test3.c
test/btree.test

index 6bf9b7ae46f0a3d6b6b0ad48d4d9206b8165fe50..5297a725c355cb694bb6e4a85ccea316916c7261 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C The\sfirst\stest\sfile\sfor\sBTree\sadded.\sSimple\sinsert\sand\sdelete\stests\spass.\nThere\sis\sstill\sa\slot\sof\swork\sto\sbe\sdone,\sthough.\s(CVS\s228)
-D 2001-06-24T20:39:41
+C More\stests\sand\sbug\sfixes\sin\sbtree.c\s(CVS\s229)
+D 2001-06-25T02:11:07
 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
 F Makefile.in 65862a30703b070209b5f5e565d75cc870962b3c
 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
@@ -12,8 +12,8 @@ F notes/notes1.txt b7c0812b704a022e88c621146ae50955c923d464
 F notes/notes2.txt 7e3fafd5e25906c1fe1e95f13b089aa398ca403e
 F notes/notes3.txt 985bf688b59f1f52bfe6e4b1f896efdeffac1432
 F src/TODO 38a68a489e56e9fd4a96263e0ff9404a47368ad4
-F src/btree.c e46ab610d0bef3d1a9f698bede21d554c42763e5
-F src/btree.h 40ae2c9b6d2ba8feb03461a589ccab9afc04ec29
+F src/btree.c 977621ad8c0607c13e4f404284ae1fb28adf542f
+F src/btree.h 2ce445f0b733e0d077377cbb49c12316e7ce524d
 F src/build.c 4f6a2d551c56342cd4a0420654835be3ad179651
 F src/dbbe.c b18259f99d87240cbe751021cf14dd3aa83a48af
 F src/dbbe.h 7235b15c6c5d8be0c4da469cef9620cee70b1cc8
@@ -45,7 +45,7 @@ F src/table.c adcaf074f6c1075e86359174e68701fa2acfc4d6
 F src/tclsqlite.c af29a45cb4c2244a6fd032568a22d26516472b2c
 F src/test1.c abb3cb427e735ae87e6533f5b3b7164b7da91bc4
 F src/test2.c 0183625225a860397b4fd3041aefb48f77e4630a
-F src/test3.c 405ea28287faeefc108ca362eca527731421e6bb
+F src/test3.c a66bb93c540d53d1026b0d183faca928d6c82ba0
 F src/tokenize.c 0118b57702cb6550769316e8443b06760b067acf
 F src/update.c 0cf789656a936d4356668393267692fa4b03ffc6
 F src/util.c 1b396ac34e30dd6222d82e996c17b161bbc906bc
@@ -53,7 +53,7 @@ F src/vdbe.c f93be4414ba892df9c5589815d2a57c1fb12c820
 F src/vdbe.h dc1205da434c6a9da03b5d6b089270bbc8e6d437
 F src/where.c 0c542fc44bd85152dfb8507862cfe2e60c629e9f
 F test/all.test 21d55a97e39e7ec5776751dc9dd8b1b51ef4a048
-F test/btree.test 8db61fdd957e906d7d237bf0f578f3e8cc9fb33e
+F test/btree.test 9207999792e0a784821fdfa1287311e3f22ff4b0
 F test/copy.test b77a1214bd7756f2849d5c4fa6e715c0ff0c34eb
 F test/dbbe.test a022fe2d983848f786e17ef1fc6809cfd37fb02c
 F test/delete.test 50b9b1f06c843d591741dba7869433a105360dbf
@@ -108,7 +108,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
 F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
 F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
 F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
-P f4df6664037c68e1ce539c84c852124d95cd5a56
-R 3068b07f88f8e6db3749d5669bb8ecc6
+P 85f015c9750a5eab274e82f0e2c6e8f09dc7ca70
+R 3996a4b0538db0f013a966fe30254459
 U drh
-Z ee5edd13b8c55ec829c3087fe59854aa
+Z 373fed59edcfc36190ad26edeac1578b
index 55e4356685c3befda4fac2fc9e4209895dc9f35b..eb975e72a0af65b721de5bc5512a063eb60dc1b2 100644 (file)
@@ -1 +1 @@
-85f015c9750a5eab274e82f0e2c6e8f09dc7ca70
\ No newline at end of file
+6b9b298b2846146b95d7df7f423867976bafa390
\ No newline at end of file
index b4666da4091931e25ffbed956ad35f4a81ad861b..d1761c5fba1baea4918c2773e66e3904e324ac89 100644 (file)
@@ -21,7 +21,7 @@
 **   http://www.hwaci.com/drh/
 **
 *************************************************************************
-** $Id: btree.c,v 1.14 2001/06/24 20:39:41 drh Exp $
+** $Id: btree.c,v 1.15 2001/06/25 02:11:07 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -141,7 +141,8 @@ struct PageOne {
   char zMagic[MAGIC_SIZE]; /* String that identifies the file as a database */
   int iMagic;              /* Integer to verify correct byte order */
   Pgno freeList;           /* First free page in a list of all free pages */
-  int aMeta[SQLITE_N_BTREE_META];  /* User defined integers */
+  int nFree;               /* Number of pages on the free list */
+  int aMeta[SQLITE_N_BTREE_META-1];  /* User defined integers */
 };
 
 /*
@@ -205,7 +206,7 @@ struct CellHdr {
 ** This number is chosen so that at least 4 cells will fit on every page.
 */
 #define MX_LOCAL_PAYLOAD \
-  ((SQLITE_PAGE_SIZE-sizeof(PageHdr))/4-(sizeof(CellHdr)+sizeof(Pgno)))
+  (((SQLITE_PAGE_SIZE-sizeof(PageHdr))/4-(sizeof(CellHdr)+sizeof(Pgno)))&~3)
 
 /*
 ** Data on a database page is stored as a linked list of Cell structures.
@@ -364,7 +365,7 @@ static void defragmentPage(MemPage *pPage){
   pPage->u.hdr.firstCell = pc;
   memcpy(newPage, pPage->u.aDisk, pc);
   for(i=0; i<pPage->nCell; i++){
-    Cell *pCell = (Cell*)&pPage->apCell[i];
+    Cell *pCell = pPage->apCell[i];
 
     /* This routine should never be called on an overfull page.  The
     ** following asserts verify that constraint. */
@@ -372,13 +373,16 @@ static void defragmentPage(MemPage *pPage){
     assert( Addr(pCell) < Addr(pPage) + SQLITE_PAGE_SIZE );
 
     n = cellSize(pCell);
-    pCell->h.iNext = i<pPage->nCell-1 ? pc + n : 0;
+    pCell->h.iNext = pc + n;
     memcpy(&newPage[pc], pCell, n);
     pPage->apCell[i] = (Cell*)&pPage->u.aDisk[pc];
     pc += n;
   }
   assert( pPage->nFree==SQLITE_PAGE_SIZE-pc );
   memcpy(pPage->u.aDisk, newPage, pc);
+  if( pPage->nCell>0 ){
+    pPage->apCell[pPage->nCell-1]->h.iNext = 0;
+  }
   pFBlk = (FreeBlk*)&pPage->u.aDisk[pc];
   pFBlk->iSize = SQLITE_PAGE_SIZE - pc;
   pFBlk->iNext = 0;
@@ -729,12 +733,11 @@ static void unlockBtree(Btree *pBt){
 }
 
 /*
-** Commit the transaction currently in progress.  All cursors
-** must be closed before this routine is called.
+** Commit the transaction currently in progress.
 */
 int sqliteBtreeCommit(Btree *pBt){
   int rc;
-  if( pBt->pCursor!=0 || pBt->inTrans==0 ) return SQLITE_ERROR;
+  if( pBt->inTrans==0 ) return SQLITE_ERROR;
   rc = sqlitepager_commit(pBt->pPager);
   pBt->inTrans = 0;
   unlockBtree(pBt);
@@ -890,7 +893,7 @@ static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){
     if( a==amt ){
       return SQLITE_OK;
     }
-    offset += a;
+    offset = 0;
     zBuf += a;
     amt -= a;
   }
@@ -910,10 +913,12 @@ static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){
         a = OVERFLOW_SIZE - offset;
       }
       memcpy(zBuf, &pOvfl->aPayload[offset], a);
+      offset = 0;
       amt -= a;
       zBuf += a;
+    }else{
+      offset -= OVERFLOW_SIZE;
     }
-    offset -= OVERFLOW_SIZE;
     sqlitepager_unref(pOvfl);
   }
   return amt==0 ? SQLITE_OK : SQLITE_CORRUPT;
@@ -1267,9 +1272,10 @@ static int allocatePage(Btree *pBt, MemPage **ppPage, Pgno *pPgno){
       return rc;
     }
     pPage1->freeList = pOvfl->iNext;
+    pPage1->nFree--;
     *ppPage = (MemPage*)pOvfl;
   }else{
-    *pPgno = sqlitepager_pagecount(pBt->pPager);
+    *pPgno = sqlitepager_pagecount(pBt->pPager) + 1;
     rc = sqlitepager_get(pBt->pPager, *pPgno, (void**)ppPage);
     if( rc ) return rc;
     rc = sqlitepager_write(*ppPage);
@@ -1294,6 +1300,7 @@ static int freePage(Btree *pBt, void *pPage, Pgno pgno){
     assert( pOvfl!=0 );
     pgno = sqlitepager_pagenumber(pOvfl);
   }
+  assert( pgno>2 );
   rc = sqlitepager_write(pPage1);
   if( rc ){
     return rc;
@@ -1311,6 +1318,7 @@ static int freePage(Btree *pBt, void *pPage, Pgno pgno){
   }
   pOvfl->iNext = pPage1->freeList;
   pPage1->freeList = pgno;
+  pPage1->nFree++;
   memset(pOvfl->aPayload, 0, OVERFLOW_SIZE);
   ((MemPage*)pPage)->isInit = 0;
   assert( ((MemPage*)pPage)->pParent==0 );
@@ -1340,7 +1348,6 @@ static int clearCell(Btree *pBt, Cell *pCell){
     rc = freePage(pBt, pOvfl, ovfl);
     if( rc ) return rc;
     ovfl = nextOvfl;
-    sqlitepager_unref(pOvfl);
   }
   return SQLITE_OK;
 }
@@ -1477,11 +1484,11 @@ static void insertCell(MemPage *pPage, int i, Cell *pCell, int sz){
   int idx, j;
   assert( i>=0 && i<=pPage->nCell );
   assert( sz==cellSize(pCell) );
+  idx = allocateSpace(pPage, sz);
   for(j=pPage->nCell; j>i; j--){
     pPage->apCell[j] = pPage->apCell[j-1];
   }
   pPage->nCell++;
-  idx = allocateSpace(pPage, sz);
   if( idx<=0 ){
     pPage->isOverfull = 1;
     pPage->apCell[i] = pCell;
@@ -2002,7 +2009,7 @@ int sqliteBtreeCreateTable(Btree *pBt, int *piTable){
 ** Erase the given database page and all its children.  Return
 ** the page to the freelist.
 */
-static int clearDatabasePage(Btree *pBt, Pgno pgno){
+static int clearDatabasePage(Btree *pBt, Pgno pgno, int freePageFlag){
   MemPage *pPage;
   int rc;
   Cell *pCell;
@@ -2015,15 +2022,22 @@ static int clearDatabasePage(Btree *pBt, Pgno pgno){
     pCell = (Cell*)&pPage->u.aDisk[idx];
     idx = pCell->h.iNext;
     if( pCell->h.leftChild ){
-      rc = clearDatabasePage(pBt, pCell->h.leftChild);
+      rc = clearDatabasePage(pBt, pCell->h.leftChild, 1);
       if( rc ) return rc;
     }
     rc = clearCell(pBt, pCell);
     if( rc ) return rc;
   }
-  rc = clearDatabasePage(pBt, pPage->u.hdr.rightChild);
-  if( rc ) return rc;
-  return freePage(pBt, pPage, pgno);
+  if( pPage->u.hdr.rightChild ){
+    rc = clearDatabasePage(pBt, pPage->u.hdr.rightChild, 1);
+    if( rc ) return rc;
+  }
+  if( freePageFlag ){
+    rc = freePage(pBt, pPage, pgno);
+  }else{
+    zeroPage(pPage);
+  }
+  return rc;
 }
 
 /*
@@ -2034,7 +2048,7 @@ int sqliteBtreeClearTable(Btree *pBt, int iTable){
   if( !pBt->inTrans ){
     return SQLITE_ERROR;  /* Must start a transaction first */
   }
-  rc = clearDatabasePage(pBt, (Pgno)iTable);
+  rc = clearDatabasePage(pBt, (Pgno)iTable, 0);
   if( rc ){
     sqliteBtreeRollback(pBt);
   }
@@ -2053,13 +2067,15 @@ int sqliteBtreeDropTable(Btree *pBt, int iTable){
     return SQLITE_ERROR;  /* Must start a transaction first */
   }
   rc = sqlitepager_get(pBt->pPager, (Pgno)iTable, (void**)&pPage);
-  if( rc==SQLITE_OK ){
-    rc = sqliteBtreeClearTable(pBt, iTable);
-  }
-  if( rc==SQLITE_OK && iTable!=2 ){
-    rc = freePage(pBt, pPage, (Pgno)iTable);
+  if( rc ) return rc;
+  rc = sqliteBtreeClearTable(pBt, iTable);
+  if( rc ) return rc;
+  if( iTable>2 ){
+    rc = freePage(pBt, pPage, iTable);
+  }else{
+    zeroPage(pPage);
+    sqlitepager_unref(pPage);
   }
-  sqlitepager_unref(pPage);
   return rc;  
 }
 
@@ -2072,7 +2088,8 @@ int sqliteBtreeGetMeta(Btree *pBt, int *aMeta){
 
   rc = sqlitepager_get(pBt->pPager, 1, (void**)&pP1);
   if( rc ) return rc;
-  memcpy(aMeta, pP1->aMeta, sizeof(pP1->aMeta));
+  aMeta[0] = pP1->nFree;
+  memcpy(&aMeta[1], pP1->aMeta, sizeof(pP1->aMeta));
   sqlitepager_unref(pP1);
   return SQLITE_OK;
 }
@@ -2088,8 +2105,8 @@ int sqliteBtreeUpdateMeta(Btree *pBt, int *aMeta){
   }
   pP1 = pBt->page1;
   rc = sqlitepager_write(pP1);
-  if( rc ) return rc;
-  memcpy(pP1->aMeta, aMeta, sizeof(pP1->aMeta));
+  if( rc ) return rc;  
+  memcpy(pP1->aMeta, &aMeta[1], sizeof(pP1->aMeta));
   return SQLITE_OK;
 }
 
@@ -2116,6 +2133,7 @@ int sqliteBtreePageDump(Btree *pBt, int pgno){
     Cell *pCell = (Cell*)&pPage->u.aDisk[idx];
     int sz = cellSize(pCell);
     sprintf(range,"%d..%d", idx, idx+sz-1);
+    sz = pCell->h.nKey + pCell->h.nData;
     if( sz>sizeof(payload)-1 ) sz = sizeof(payload)-1;
     memcpy(payload, pCell->aPayload, sz);
     for(j=0; j<sz; j++){
@@ -2125,8 +2143,11 @@ int sqliteBtreePageDump(Btree *pBt, int pgno){
     printf(
       "cell %2d: i=%-10s chld=%-4d nk=%-3d nd=%-3d payload=%s\n",
       i, range, (int)pCell->h.leftChild, pCell->h.nKey, pCell->h.nData,
-      pCell->aPayload
+      payload
     );
+    if( pPage->apCell[i]!=pCell ){
+      printf("**** apCell[%d] does not match on prior entry ****\n", i);
+    }
     i++;
     idx = pCell->h.iNext;
   }
@@ -2144,6 +2165,7 @@ int sqliteBtreePageDump(Btree *pBt, int pgno){
     printf("freeblock %2d: i=%-10s size=%-4d total=%d\n",
        i, range, p->iSize, nFree);
     idx = p->iNext;
+    i++;
   }
   if( idx!=0 ){
     printf("ERROR: next freeblock index out of range: %d\n", idx);
@@ -2155,12 +2177,40 @@ int sqliteBtreePageDump(Btree *pBt, int pgno){
 
 #ifdef SQLITE_TEST
 /*
-** Put the page number and index of a cursor into aResult[0] and aResult[1]
-** This routine is used for debugging and testing only.
+** Fill aResult[] with information about the entry and page that the
+** cursor is pointing to.
+** 
+**   aResult[0] =  The page number
+**   aResult[1] =  The entry number
+**   aResult[2] =  Total number of entries on this page
+**   aResult[3] =  Size of this entry
+**   aResult[4] =  Number of free bytes on this page
+**   aResult[5] =  Number of free blocks on the page
+**   aResult[6] =  Page number of the left child of this entry
+**   aResult[7] =  Page number of the right child for the whole page
 */
 int sqliteBtreeCursorDump(BtCursor *pCur, int *aResult){
-  aResult[0] = sqlitepager_pagenumber(pCur->pPage);
+  int cnt, idx;
+  MemPage *pPage = pCur->pPage;
+  aResult[0] = sqlitepager_pagenumber(pPage);
   aResult[1] = pCur->idx;
+  aResult[2] = pPage->nCell;
+  if( pCur->idx>=0 && pCur->idx<pPage->nCell ){
+    aResult[3] = cellSize(pPage->apCell[pCur->idx]);
+    aResult[6] = pPage->apCell[pCur->idx]->h.leftChild;
+  }else{
+    aResult[3] = 0;
+    aResult[6] = 0;
+  }
+  aResult[4] = pPage->nFree;
+  cnt = 0;
+  idx = pPage->u.hdr.firstFree;
+  while( idx>0 && idx<SQLITE_PAGE_SIZE ){
+    cnt++;
+    idx = ((FreeBlk*)&pPage->u.aDisk[idx])->iNext;
+  }
+  aResult[5] = cnt;
+  aResult[7] = pPage->u.hdr.rightChild;
   return SQLITE_OK;
 }
 #endif
index b751c2f8437af9bcc05ea495db6cf77b8f6c0c56..17f74009380121bda08233ccb165382655ab0df1 100644 (file)
@@ -24,7 +24,7 @@
 ** This header file defines the interface that the sqlite B-Tree file
 ** subsystem.
 **
-** @(#) $Id: btree.h,v 1.5 2001/06/22 19:15:00 drh Exp $
+** @(#) $Id: btree.h,v 1.6 2001/06/25 02:11:07 drh Exp $
 */
 
 typedef struct Btree Btree;
@@ -52,7 +52,7 @@ int sqliteBtreeDataSize(BtCursor*, int *pSize);
 int sqliteBtreeData(BtCursor*, int offset, int amt, char *zBuf);
 int sqliteBtreeCloseCursor(BtCursor*);
 
-#define SQLITE_N_BTREE_META 3
+#define SQLITE_N_BTREE_META 4
 int sqliteBtreeGetMeta(Btree*, int*);
 int sqliteBtreeUpdateMeta(Btree*, int*);
 
index 87b36e37e5f73d3bd18c59438e301181bfeae42a..02c965a7403099eb262c788ebbf209931e54200b 100644 (file)
@@ -25,7 +25,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test3.c,v 1.2 2001/06/22 19:15:01 drh Exp $
+** $Id: test3.c,v 1.3 2001/06/25 02:11:07 drh Exp $
 */
 #include "sqliteInt.h"
 #include "pager.h"
@@ -610,8 +610,17 @@ static int btree_data(
 /*
 ** Usage:   btree_cursor_dump ID
 **
-** Return two integers which are the page number and cell index for
-** the given cursor.
+** Return eight integers containing information about the entry the
+** cursor is pointing to:
+**
+**   aResult[0] =  The page number
+**   aResult[1] =  The entry number
+**   aResult[2] =  Total number of entries on this page
+**   aResult[3] =  Size of this entry
+**   aResult[4] =  Number of free bytes on this page
+**   aResult[5] =  Number of free blocks on the page
+**   aResult[6] =  Page number of the left child of this entry
+**   aResult[7] =  Page number of the right child for the whole page
 */
 static int btree_cursor_dump(
   void *NotUsed,
@@ -621,8 +630,9 @@ static int btree_cursor_dump(
 ){
   BtCursor *pCur;
   int rc;
-  int aResult[2];
-  char zBuf[50];
+  int i, j;
+  int aResult[8];
+  char zBuf[400];
 
   if( argc!=2 ){
     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
@@ -635,8 +645,12 @@ static int btree_cursor_dump(
     Tcl_AppendResult(interp, errorName(rc), 0);
     return TCL_ERROR;
   }
-  sprintf(zBuf,"%d %d",aResult[0], aResult[1]);
-  Tcl_AppendResult(interp, zBuf, 0);
+  j = 0;
+  for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){
+    sprintf(&zBuf[j]," %d", aResult[i]);
+    j += strlen(&zBuf[j]);
+  }
+  Tcl_AppendResult(interp, &zBuf[1], 0);
   return SQLITE_OK;
 }
 
index bf849f22376ef47673c965b5b7a01db971f9655f..2167d4a71b1d371377a95a9889f6c876ffc9388b 100644 (file)
@@ -23,7 +23,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this script is btree database backend
 #
-# $Id: btree.test,v 1.1 2001/06/24 20:39:41 drh Exp $
+# $Id: btree.test,v 1.2 2001/06/25 02:11:07 drh Exp $
 
 
 set testdir [file dirname $argv0]
@@ -287,9 +287,7 @@ do_test btree-4.4 {
 # Commit and make sure the delete is still there.
 #
 do_test btree-4.5 {
-  btree_close_cursor $::c1
   btree_commit $::b1
-  set ::c1 [btree_cursor $::b1 2]
   btree_move_to $::c1 {}
   set r {}
   while 1 {
@@ -302,13 +300,278 @@ do_test btree-4.5 {
   set r   
 } {five 5.00 four 4.00 six 6.00 three 3.00 two 2.00}
 
+# Completely close the database and reopen it.  Then check
+# the data again.
+#
+do_test btree-4.6 {
+  btree_close_cursor $::c1
+  btree_close $::b1
+  set ::b1 [btree_open test1.bt]
+  set ::c1 [btree_cursor $::b1 2]
+  set r {}
+  while 1 {
+    set key [btree_key $::c1]
+    if {$key==""} break
+    lappend r $key
+    lappend r [btree_data $::c1]
+    btree_next $::c1
+  }
+  set r   
+} {five 5.00 four 4.00 six 6.00 three 3.00 two 2.00}
 
+# Try to read and write meta data
+#
+do_test btree-5.1 {
+  btree_get_meta $::b1
+} {0 0 0 0}
+do_test btree-5.2 {
+  set rc [catch {btree_update_meta $::b1 1 2 3 4} msg]
+  lappend rc $msg
+} {1 SQLITE_ERROR}
+do_test btree-5.3 {
+  btree_begin_transaction $::b1
+  set rc [catch {btree_update_meta $::b1 1 2 3 4} msg]
+  lappend rc $msg
+} {0 {}}
+do_test btree-5.4 {
+  btree_get_meta $::b1
+} {0 2 3 4}
+do_test btree-5.5 {
+  btree_close_cursor $::c1
+  btree_rollback $::b1
+  btree_get_meta $::b1
+} {0 0 0 0}
+do_test btree-5.6 {
+  btree_begin_transaction $::b1
+  btree_update_meta $::b1 999 10 20 30
+  btree_commit $::b1
+  btree_get_meta $::b1
+} {0 10 20 30}
 
+proc select_all {cursor} {
+  set r {}
+  btree_move_to $cursor {}
+  while 1 {
+    set key [btree_key $cursor]
+    if {$key==""} break
+    lappend r $key
+    lappend r [btree_data $cursor]
+    btree_next $cursor
+  }
+  return $r
+}
 
-do_test btree-99.1 {
+# Try to create a new table in the database file
+#
+do_test btree-6.1 {
+  set rc [catch {btree_create_table $::b1} msg]
+  lappend rc $msg
+} {1 SQLITE_ERROR}
+do_test btree-6.2 {
+  btree_begin_transaction $::b1
+  set ::t2 [btree_create_table $::b1]
+} {3}
+do_test btree-6.2.1 {
+  set ::c2 [btree_cursor $::b1 $::t2]
+  btree_insert $::c2 ten 10
+  btree_key $::c2
+} {ten}
+do_test btree-6.3 {
+  btree_commit $::b1
+  set ::c1 [btree_cursor $::b1 2]
+  select_all $::c1
+} {five 5.00 four 4.00 six 6.00 three 3.00 two 2.00}
+#btree_page_dump $::b1 3
+do_test btree-6.4 {
+  select_all $::c2
+} {ten 10}
+
+# Drop the new table, then create it again anew.
+#
+do_test btree-6.5 {
+  btree_begin_transaction $::b1
+} {}
+do_test btree-6.6 {
+  btree_close_cursor $::c2
+} {}
+do_test btree-6.7 {
+  btree_drop_table $::b1 $::t2
+} {}
+do_test btree-6.7.1 {
+  lindex [btree_get_meta $::b1] 0
+} {1}
+do_test btree-6.8 {
+  set ::t2 [btree_create_table $::b1]
+} {3}
+do_test btree-6.8.1 {
+  lindex [btree_get_meta $::b1] 0
+} {0}
+do_test btree-6.9 {
+  set ::c2 [btree_cursor $::b1 $::t2]
+  btree_move_to $::c2 {}
+  btree_key $::c2
+} {}
+
+# If we drop table 2 it just clears the table.  Table 2 always exists.
+#
+do_test btree-6.10 {
+  btree_close_cursor $::c1
+  btree_drop_table $::b1 2
+  set ::c1 [btree_cursor $::b1 2]
+  btree_move_to $::c1 {}
+  btree_key $::c1
+} {}
+do_test btree-6.11 {
+  btree_commit $::b1
+  select_all $::c1
+} {}
+do_test btree-6.12 {
+  select_all $::c2
+} {}
+
+# Check to see that pages defragment properly.  To do this test we will
+# 
+#   1.  Fill the first page table 2 with data.
+#   2.  Delete every other entry of table 2. 
+#   3.  Insert a single entry that requires more contiguous
+#       space than is available.
+#
+do_test btree-7.1 {
+  btree_begin_transaction $::b1
+} {}
+do_test btree-7.2 {
+  for {set i 0} {$i<36} {incr i} {
+    set key [format %03d $i]
+    set data "*** $key ***"
+    btree_insert $::c1 $key $data
+  }
+  lrange [btree_cursor_dump $::c1] 4 5
+} {8 1}
+do_test btree-7.3 {
+  btree_move_to $::c1 000
+  while {[btree_key $::c1]!=""} {
+    btree_delete $::c1
+    btree_next $::c1
+    btree_next $::c1
+  }
+  lrange [btree_cursor_dump $::c1] 4 5
+} {512 19}
+#btree_page_dump $::b1 2
+do_test btree-7.4 {
+  btree_insert $::c1 018 {*** 018 ***+++}
+  btree_key $::c1
+} {018}
+do_test btree-7.5 {
+  lrange [btree_cursor_dump $::c1] 4 5
+} {480 1}
+#btree_page_dump $::b1 2
+
+# Delete an entry to make a hole of a known size, then immediately recreate
+# that entry.  This tests the path into allocateSpace where the hole exactly
+# matches the size of the desired space.
+#
+do_test btree-7.6 {
+  btree_move_to $::c1 007
+  btree_delete $::c1
+  btree_move_to $::c1 011
+  btree_delete $::c1
+} {}
+do_test btree-7.7 {
+  lindex [btree_cursor_dump $::c1] 5
+} {3}
+#btree_page_dump $::b1 2
+do_test btree-7.8 {
+  btree_insert $::c1 007 {*** 007 ***}
+  lindex [btree_cursor_dump $::c1] 5
+} {2}
+#btree_page_dump $::b1 2
+
+# Make sure the freeSpace() routine properly coaleses adjacent memory blocks
+#
+do_test btree-7.9 {
+  btree_move_to $::c1 013
+  btree_delete $::c1
+  lrange [btree_cursor_dump $::c1] 4 5
+} {536 2}
+do_test btree-7.10 {
+  btree_move_to $::c1 009
+  btree_delete $::c1
+  lrange [btree_cursor_dump $::c1] 4 5
+} {564 2}
+do_test btree-7.11 {
+  btree_move_to $::c1 018
+  btree_delete $::c1
+  lrange [btree_cursor_dump $::c1] 4 5
+} {596 2}
+do_test btree-7.13 {
+  btree_move_to $::c1 033
+  btree_delete $::c1
+  lrange [btree_cursor_dump $::c1] 4 5
+} {624 3}
+do_test btree-7.14 {
+  btree_move_to $::c1 035
+  btree_delete $::c1
+  lrange [btree_cursor_dump $::c1] 4 5
+} {652 2}
+#btree_page_dump $::b1 2
+
+# Check to see that both key and data on overflow pages work correctly.
+#
+do_test btree-8.1 {
+  set data "*** This is a very long key "
+  while {[string length $data]<256} {append data $data}
+  set ::data $data
+  btree_insert $::c1 020 $data
+} {}
+#btree_page_dump $::b1 2
+do_test btree-8.2 {
+  string length [btree_data $::c1]
+} [string length $::data]
+do_test btree-8.3 {
+  btree_data $::c1
+} $::data
+do_test btree-8.4 {
+  btree_delete $::c1
+} {}
+do_test btree-8.4.1 {
+  lindex [btree_get_meta $::b1] 0
+} [expr {int(([string length $::data]-238+1019)/1020)}]
+do_test btree-8.5 {
+  set data "*** This is an even longer key"
+  while {[string length $data]<2000} {append data $data}
+  set ::data $data
+  btree_insert $::c1 020 $data
+} {}
+do_test btree-8.6 {
+  string length [btree_data $::c1]
+} [string length $::data]
+do_test btree-8.7 {
+  btree_data $::c1
+} $::data
+do_test btree-8.8 {
+  btree_commit $::b1
+  btree_data $::c1
+} $::data
+do_test btree-8.9 {
+  btree_close_cursor $::c1
   btree_close $::b1
+  set ::b1 [btree_open test1.bt]
+  set ::c1 [btree_cursor $::b1 2]
+  btree_move_to $::c1 020
+  btree_data $::c1
+} $::data
+do_test btree-8.10 {
+  btree_begin_transaction $::b1
+  btree_delete $::c1
 } {}
+do_test btree-8.11 {
+  lindex [btree_get_meta $::b1] 0
+} [expr {int(([string length $::data]-238+1019)/1020)}]
+puts [btree_get_meta $::b1]
 
+do_test btree-99.1 {
+  btree_close $::b1
+} {}
 
 } ;# end if( not mem: and has pager_open command );