/ Check-in [1da361fa]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Support root-page allocation/deallocation in auto-vacuum databases. Still a few problems. (CVS 2054)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:1da361fae82d420be63c53f8e3efaccac24f348a
User & Date: danielk1977 2004-11-04 14:30:05
Context
2004-11-04
14:47
All tests pass when SQLITE_OMIT_INTEGRITY_CHECK is defined. (CVS 2055) check-in: 158a2d16 user: drh tags: trunk
14:30
Support root-page allocation/deallocation in auto-vacuum databases. Still a few problems. (CVS 2054) check-in: 1da361fa user: danielk1977 tags: trunk
04:42
All tests pass even if OMIT_TRIGGER is defined. (CVS 2053) check-in: c33b3a61 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree.c,v 1.203 2004/11/04 02:57:34 danielk1977 Exp $
           12  +** $Id: btree.c,v 1.204 2004/11/04 14:30:05 danielk1977 Exp $
    13     13   **
    14     14   ** This file implements a external (disk-based) database using BTrees.
    15     15   ** For a detailed discussion of BTrees, refer to
    16     16   **
    17     17   **     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
    18     18   **     "Sorting And Searching", pages 473-480. Addison-Wesley
    19     19   **     Publishing Company, Reading, Massachusetts.
................................................................................
  1620   1620     Pgno iFreePage
  1621   1621   ){
  1622   1622     MemPage *pPtrPage;   /* The page that contains a pointer to pDbPage */
  1623   1623     Pgno iDbPage = pDbPage->pgno;
  1624   1624     Pager *pPager = pBt->pPager;
  1625   1625     int rc;
  1626   1626   
  1627         -  assert( eType==PTRMAP_OVERFLOW2 
  1628         -      || eType==PTRMAP_OVERFLOW1 || eType==PTRMAP_BTREE );
         1627  +  assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 || 
         1628  +      eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE );
  1629   1629   
  1630   1630     /* Move page iDbPage from it's current location to page number iFreePage */
  1631   1631     TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", 
  1632   1632         iDbPage, iFreePage, iPtrPage, eType));
  1633   1633     rc = sqlite3pager_movepage(pPager, pDbPage->aData, iFreePage);
  1634   1634     if( rc!=SQLITE_OK ){
  1635   1635       return rc;
................................................................................
  1640   1640     ** that point to overflow pages. The pointer map entries for all these
  1641   1641     ** pages need to be changed.
  1642   1642     **
  1643   1643     ** If pDbPage is an overflow page, then the first 4 bytes may store a
  1644   1644     ** pointer to a subsequent overflow page. If this is the case, then
  1645   1645     ** the pointer map needs to be updated for the subsequent overflow page.
  1646   1646     */
  1647         -  if( eType==PTRMAP_BTREE ){
         1647  +  if( eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE ){
  1648   1648       rc = setChildPtrmaps(pDbPage);
  1649   1649       if( rc!=SQLITE_OK ){
  1650   1650         return rc;
  1651   1651       }
  1652   1652     }else{
  1653   1653       Pgno nextOvfl = get4byte(pDbPage->aData);
  1654   1654       if( nextOvfl!=0 ){
................................................................................
  1660   1660       }
  1661   1661     }
  1662   1662   
  1663   1663     /* Fix the database pointer on page iPtrPage that pointed at iDbPage so
  1664   1664     ** that it points at iFreePage. Also fix the pointer map entry for
  1665   1665     ** iPtrPage.
  1666   1666     */
  1667         -  rc = getPage(pBt, iPtrPage, &pPtrPage);
  1668         -  if( rc!=SQLITE_OK ){
  1669         -    return rc;
  1670         -  }
  1671         -  rc = sqlite3pager_write(pPtrPage->aData);
  1672         -  if( rc!=SQLITE_OK ){
         1667  +  if( eType!=PTRMAP_ROOTPAGE ){
         1668  +    rc = getPage(pBt, iPtrPage, &pPtrPage);
         1669  +    if( rc!=SQLITE_OK ){
         1670  +      return rc;
         1671  +    }
         1672  +    rc = sqlite3pager_write(pPtrPage->aData);
         1673  +    if( rc!=SQLITE_OK ){
         1674  +      releasePage(pPtrPage);
         1675  +      return rc;
         1676  +    }
         1677  +    modifyPagePointer(pPtrPage, iDbPage, iFreePage, eType);
         1678  +    rc = ptrmapPut(pBt, iFreePage, eType, iPtrPage);
  1673   1679       releasePage(pPtrPage);
  1674         -    return rc;
  1675   1680     }
  1676         -  modifyPagePointer(pPtrPage, iDbPage, iFreePage, eType);
  1677         -  rc = ptrmapPut(pBt, iFreePage, eType, iPtrPage);
  1678         -  releasePage(pPtrPage);
  1679   1681     return rc;
  1680   1682   }
  1681   1683   
  1682   1684   /* Forward declaration required by autoVacuumCommit(). */
  1683   1685   static int allocatePage(Btree *, MemPage **, Pgno *, Pgno);
  1684   1686   
  1685   1687   /*
................................................................................
  1719   1721   
  1720   1722     origSize = sqlite3pager_pagecount(pPager);
  1721   1723     nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5);
  1722   1724     finSize = origSize - nFreeList - nPtrMap;
  1723   1725   
  1724   1726     TRACE(("AUTOVACUUM: Begin (db size %d->%d)\n", origSize, finSize));
  1725   1727   
         1728  +#if 0
  1726   1729     /* Note: This is temporary code for use during development of auto-vacuum. 
  1727   1730     **
  1728   1731     ** Inspect the pointer map to make sure there are no root pages with a
  1729   1732     ** page number greater than finSize. If so, the auto-vacuum cannot
  1730   1733     ** proceed. This limitation will be fixed when root pages are automatically
  1731   1734     ** allocated at the start of the database file.
  1732   1735     */
................................................................................
  1734   1737       rc = ptrmapGet(pBt, i, &eType, 0);
  1735   1738       if( rc!=SQLITE_OK ) goto autovacuum_out;
  1736   1739       if( eType==PTRMAP_ROOTPAGE ){
  1737   1740         TRACE(("AUTOVACUUM: Cannot proceed due to root-page on page %d\n", i));
  1738   1741         return SQLITE_OK;
  1739   1742       }
  1740   1743     }
         1744  +#endif
  1741   1745   
  1742   1746     /* Variable 'finSize' will be the size of the file in pages after
  1743   1747     ** the auto-vacuum has completed (the current file size minus the number
  1744   1748     ** of pages on the free list). Loop through the pages that lie beyond
  1745   1749     ** this mark, and if they are not already on the free list, move them
  1746   1750     ** to a free page earlier in the file (somewhere before finSize).
  1747   1751     */
................................................................................
  4283   4287   
  4284   4288         releasePage(pPageMove);
  4285   4289         rc = getPage(pBt, pgnoRoot, &pRoot);
  4286   4290         if( rc!=SQLITE_OK ){
  4287   4291           return rc;
  4288   4292         }
  4289   4293         rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage);
         4294  +      assert( eType!=PTRMAP_ROOTPAGE );
  4290   4295         if( rc!=SQLITE_OK ){
  4291   4296           releasePage(pRoot);
  4292   4297           return rc;
  4293   4298         }
  4294   4299         rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove);
  4295   4300         releasePage(pRoot);
  4296   4301         if( rc!=SQLITE_OK ){
................................................................................
  4404   4409   ** Erase all information in a table and add the root of the table to
  4405   4410   ** the freelist.  Except, the root of the principle table (the one on
  4406   4411   ** page 1) is never added to the freelist.
  4407   4412   **
  4408   4413   ** This routine will fail with SQLITE_LOCKED if there are any open
  4409   4414   ** cursors on the table.
  4410   4415   */
  4411         -int sqlite3BtreeDropTable(Btree *pBt, int iTable){
         4416  +int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){
  4412   4417     int rc;
  4413         -  MemPage *pPage;
         4418  +  MemPage *pPage = 0;
  4414   4419     BtCursor *pCur;
  4415         -/* TODO: Disallow schema modifications if there are open cursors */
         4420  +
  4416   4421     if( pBt->inTrans!=TRANS_WRITE ){
  4417   4422       return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
  4418   4423     }
         4424  +
         4425  +/* TODO: Disallow schema modifications if there are open cursors */
  4419   4426     for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
  4420   4427       if( pCur->pgnoRoot==(Pgno)iTable ){
  4421   4428         return SQLITE_LOCKED;  /* Cannot drop a table that has a cursor */
  4422   4429       }
  4423   4430     }
         4431  +
  4424   4432     rc = getPage(pBt, (Pgno)iTable, &pPage);
  4425   4433     if( rc ) return rc;
  4426   4434     rc = sqlite3BtreeClearTable(pBt, iTable);
  4427   4435     if( rc ) return rc;
         4436  +
         4437  +  if( piMoved ) *piMoved = 0;
         4438  +
  4428   4439     if( iTable>1 ){
         4440  +#ifdef SQLITE_OMIT_AUTOVACUUM
  4429   4441       rc = freePage(pPage);
         4442  +    releasePage(pPage);
         4443  +#else
         4444  +    if( pBt->autoVacuum ){
         4445  +      Pgno maxRootPgno;
         4446  +      rc = sqlite3BtreeGetMeta(pBt, 4, &maxRootPgno);
         4447  +      if( rc!=SQLITE_OK ){
         4448  +        releasePage(pPage);
         4449  +        return rc;
         4450  +      }
         4451  +
         4452  +      if( iTable==maxRootPgno ){
         4453  +        /* If the table being dropped is the table with the largest root-page
         4454  +        ** number in the database, put the root page on the free list. 
         4455  +        */
         4456  +        rc = freePage(pPage);
         4457  +        releasePage(pPage);
         4458  +        if( rc!=SQLITE_OK ){
         4459  +          return rc;
         4460  +        }
         4461  +      }else{
         4462  +        /* The table being dropped does not have the largest root-page
         4463  +        ** number in the database. So move the page that does into the 
         4464  +        ** gap left by the deleted root-page.
         4465  +        */
         4466  +        MemPage *pMove;
         4467  +        releasePage(pPage);
         4468  +        rc = getPage(pBt, maxRootPgno, &pMove);
         4469  +        if( rc!=SQLITE_OK ){
         4470  +          return rc;
         4471  +        }
         4472  +        rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable);
         4473  +        releasePage(pMove);
         4474  +        if( rc!=SQLITE_OK ){
         4475  +          return rc;
         4476  +        }
         4477  +        rc = getPage(pBt, maxRootPgno, &pMove);
         4478  +        if( rc!=SQLITE_OK ){
         4479  +          return rc;
         4480  +        }
         4481  +        rc = freePage(pMove);
         4482  +        releasePage(pMove);
         4483  +        if( rc!=SQLITE_OK ){
         4484  +          return rc;
         4485  +        }
         4486  +        *piMoved = maxRootPgno;
         4487  +      }
         4488  +
         4489  +      rc = sqlite3BtreeUpdateMeta(pBt, 4, maxRootPgno-1);
         4490  +    }else{
         4491  +      rc = freePage(pPage);
         4492  +      releasePage(pPage);
         4493  +    }
         4494  +#endif
  4430   4495     }else{
         4496  +    /* If sqlite3BtreeDropTable was called on page 1. */
  4431   4497       zeroPage(pPage, PTF_INTKEY|PTF_LEAF );
         4498  +    releasePage(pPage);
  4432   4499     }
  4433         -  releasePage(pPage);
  4434   4500     return rc;  
  4435   4501   }
  4436   4502   
  4437   4503   
  4438   4504   /*
  4439   4505   ** Read the meta-information out of a database file.  Meta[0]
  4440   4506   ** is the number of free pages currently in the database.  Meta[1]

Changes to src/btree.h.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This header file defines the interface that the sqlite B-Tree file
    13     13   ** subsystem.  See comments in the source code for a detailed description
    14     14   ** of what each interface routine does.
    15     15   **
    16         -** @(#) $Id: btree.h,v 1.58 2004/07/23 00:01:39 drh Exp $
           16  +** @(#) $Id: btree.h,v 1.59 2004/11/04 14:30:05 danielk1977 Exp $
    17     17   */
    18     18   #ifndef _BTREE_H_
    19     19   #define _BTREE_H_
    20     20   
    21     21   /* TODO: This definition is just included so other modules compile. It
    22     22   ** needs to be revisited.
    23     23   */
................................................................................
    68     68   /* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
    69     69   ** of the following flags:
    70     70   */
    71     71   #define BTREE_INTKEY     1    /* Table has only 64-bit signed integer keys */
    72     72   #define BTREE_ZERODATA   2    /* Table has keys only - no data */
    73     73   #define BTREE_LEAFDATA   4    /* Data stored in leaves only.  Implies INTKEY */
    74     74   
    75         -int sqlite3BtreeDropTable(Btree*, int);
           75  +int sqlite3BtreeDropTable(Btree*, int, int*);
    76     76   int sqlite3BtreeClearTable(Btree*, int);
    77     77   int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
    78     78   int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
    79     79   
    80     80   int sqlite3BtreeCursor(
    81     81     Btree*,                              /* BTree containing table to open */
    82     82     int iTable,                          /* Index of root page */

Changes to src/build.c.

    19     19   **     DROP INDEX
    20     20   **     creating ID lists
    21     21   **     BEGIN TRANSACTION
    22     22   **     COMMIT
    23     23   **     ROLLBACK
    24     24   **     PRAGMA
    25     25   **
    26         -** $Id: build.c,v 1.258 2004/10/31 02:22:49 drh Exp $
           26  +** $Id: build.c,v 1.259 2004/11/04 14:30:05 danielk1977 Exp $
    27     27   */
    28     28   #include "sqliteInt.h"
    29     29   #include <ctype.h>
    30     30   
    31     31   /*
    32     32   ** This routine is called when a new SQL statement is beginning to
    33     33   ** be parsed.  Check to see if the schema for the database needs
................................................................................
  1549   1549       }
  1550   1550     }
  1551   1551     DbClearProperty(db, idx, DB_UnresetViews);
  1552   1552   }
  1553   1553   #else
  1554   1554   # define sqliteViewResetAll(A,B)
  1555   1555   #endif /* SQLITE_OMIT_VIEW */
         1556  +
         1557  +/*
         1558  +** This function is called by the VDBE to adjust the internal schema
         1559  +** used by SQLite when the btree layer moves a table root page. The
         1560  +** root-page of a table or index in database iDb has changed from iFrom
         1561  +** to iTo.
         1562  +*/
         1563  +#ifndef SQLITE_OMIT_AUTOVACUUM
         1564  +void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
         1565  +  HashElem *pElem;
         1566  +  
         1567  +  for(pElem=sqliteHashFirst(&pDb->tblHash); pElem; pElem=sqliteHashNext(pElem)){
         1568  +    Table *pTab = sqliteHashData(pElem);
         1569  +    if( pTab->tnum==iFrom ){
         1570  +      pTab->tnum = iTo;
         1571  +      return;
         1572  +    }
         1573  +  }
         1574  +  for(pElem=sqliteHashFirst(&pDb->idxHash); pElem; pElem=sqliteHashNext(pElem)){
         1575  +    Index *pIdx = sqliteHashData(pElem);
         1576  +    if( pIdx->tnum==iFrom ){
         1577  +      pIdx->tnum = iTo;
         1578  +      return;
         1579  +    }
         1580  +  }
         1581  +  assert(0);
         1582  +}
         1583  +#endif
         1584  +
         1585  +/*
         1586  +** Write code to erase the table with root-page iTable from database iDb.
         1587  +** Also write code to modify the sqlite_master table and internal schema
         1588  +** if a root-page of another table is moved by the btree-layer whilst
         1589  +** erasing iTable (this can happen with an auto-vacuum database).
         1590  +*/ 
         1591  +static void destroyRootPage(Vdbe *v, int iTable, int iDb){
         1592  +#ifndef SQLITE_OMIT_AUTOVACUUM
         1593  +  int base;
         1594  +#endif
         1595  +  sqlite3VdbeAddOp(v, OP_Destroy, iTable, iDb);
         1596  +#ifndef SQLITE_OMIT_AUTOVACUUM
         1597  +  /* If SQLITE_OMIT_AUTOVACUUM is not defined, then OP_Destroy pushes
         1598  +  ** an integer onto the stack. If this integer is non-zero, then it is
         1599  +  ** the root page number of a table moved to location iTable. The 
         1600  +  ** following writes VDBE code to modify the sqlite_master table to
         1601  +  ** reflect this. It is assumed that cursor number 0 is a write-cursor
         1602  +  ** opened on the sqlite_master table.
         1603  +  */
         1604  +  static const VdbeOpList updateMaster[] = {
         1605  +    /* If the Op_Destroy pushed a 0 onto the stack, then skip the following
         1606  +    ** code. sqlite_master does not need updating in this case.
         1607  +    */
         1608  +    { OP_Dup,        0, 0,        0},
         1609  +    { OP_Integer,    0, 0,        0},
         1610  +    { OP_Eq,         0, ADDR(17), 0},
         1611  +
         1612  +    /* Search for the sqlite_master row containing root-page iTable. */
         1613  +    { OP_Rewind,     0, ADDR(8), 0}, 
         1614  +    { OP_Dup,        0, 0,       0}, /* 4 */
         1615  +    { OP_Column,     0, 3,       0}, /* 5 */
         1616  +    { OP_Eq,         0, ADDR(9), 0},
         1617  +    { OP_Next,       0, ADDR(4), 0},
         1618  +    { OP_Halt,       SQLITE_CORRUPT, OE_Fail, 0}, /* 8 */
         1619  +    { OP_Recno,      0, 0,       0}, /* 9 */
         1620  +
         1621  +    /* Cursor 0 now points at the row that will be updated. The top of
         1622  +    ** the stack is the rowid of that row. The next value on the stack is 
         1623  +    ** the new value for the root-page field.
         1624  +    */
         1625  +    { OP_Column,     0, 0,       0}, /* 10 */
         1626  +    { OP_Column,     0, 1,       0},
         1627  +    { OP_Column,     0, 2,       0},
         1628  +    { OP_Integer,    4, 0,       0}, /* 13 */
         1629  +    { OP_Column,     0, 4,       0},
         1630  +    { OP_MakeRecord, 5, 0,       0},
         1631  +    { OP_PutIntKey,  0, 0,       0}  /* 16 */
         1632  +  };
         1633  +
         1634  +  base = sqlite3VdbeAddOpList(v, ArraySize(updateMaster), updateMaster);
         1635  +  sqlite3VdbeChangeP1(v, base+13, iTable);
         1636  +#endif
         1637  +}
         1638  +
         1639  +/*
         1640  +** Write VDBE code to erase table pTab and all associated indices on disk.
         1641  +** Code to update the sqlite_master tables and internal schema definitions
         1642  +** in case a root-page belonging to another table is moved by the btree layer
         1643  +** is also added (this can happen with an auto-vacuum database).
         1644  +*/
         1645  +static void destroyTable(Vdbe *v, Table *pTab){
         1646  +#ifdef SQLITE_OMIT_AUTOVACUUM
         1647  +  destroyRootPage(v, pTab->tnum, pTab->iDb);
         1648  +  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
         1649  +    destroyRootPage(v, pIdx->tnum, pIdx->iDb);
         1650  +  }
         1651  +#else
         1652  +  /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
         1653  +  ** is not defined), then it is important to call OP_Destroy on the
         1654  +  ** table and index root-pages in order, starting with the numerically 
         1655  +  ** largest root-page number. This guarantees that none of the root-pages
         1656  +  ** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the
         1657  +  ** following were coded:
         1658  +  **
         1659  +  ** OP_Destroy 4 0
         1660  +  ** ...
         1661  +  ** OP_Destroy 5 0
         1662  +  **
         1663  +  ** and root page 5 happened to be the largest root-page number in the
         1664  +  ** database, then root page 5 would be moved to page 4 by the 
         1665  +  ** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
         1666  +  ** a free-list page.
         1667  +  */
         1668  +  int iTab = pTab->tnum;
         1669  +  int iDestroyed = 0;
         1670  +
         1671  +  while( 1 ){
         1672  +    Index *pIdx;
         1673  +    int iLargest = 0;
         1674  +
         1675  +    if( iDestroyed==0 || iTab<iDestroyed ){
         1676  +      iLargest = iTab;
         1677  +    }
         1678  +    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
         1679  +      int iIdx = pIdx->tnum;
         1680  +      assert( pIdx->iDb==pTab->iDb );
         1681  +      if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
         1682  +        iLargest = iIdx;
         1683  +      }
         1684  +    }
         1685  +    if( iLargest==0 ) return;
         1686  +    destroyRootPage(v, iLargest, pTab->iDb);
         1687  +    iDestroyed = iLargest;
         1688  +  }
         1689  +#endif
         1690  +}
  1556   1691   
  1557   1692   /*
  1558   1693   ** This routine is called to do the work of a DROP TABLE statement.
  1559   1694   ** pName is the name of the table to be dropped.
  1560   1695   */
  1561   1696   void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){
  1562   1697     Table *pTab;
................................................................................
  1631   1766         { OP_Column,     0, 2,        0}, /* sqlite_master.type */
  1632   1767         { OP_Eq,         0, ADDR(12), 0},
  1633   1768         { OP_Delete,     0, 0,        0},
  1634   1769         { OP_Rewind,     0, ADDR(13), 0},
  1635   1770         { OP_Goto,       0, ADDR(3),  0},
  1636   1771         { OP_Next,       0, ADDR(3),  0}, /* 12 */
  1637   1772       };
  1638         -    Index *pIdx;
         1773  +    /* Index *pIdx; */
  1639   1774       Trigger *pTrigger;
  1640   1775       sqlite3BeginWriteOperation(pParse, 0, pTab->iDb);
  1641   1776   
  1642   1777       /* Drop all triggers associated with the table being dropped. Code
  1643   1778       ** is generated to remove entries from sqlite_master and/or
  1644   1779       ** sqlite_temp_master if required.
  1645   1780       */
................................................................................
  1657   1792       ** created in the temp database that refers to a table in another
  1658   1793       ** database.
  1659   1794       */
  1660   1795       sqlite3OpenMasterTable(v, pTab->iDb);
  1661   1796       base = sqlite3VdbeAddOpList(v, ArraySize(dropTable), dropTable);
  1662   1797       sqlite3VdbeChangeP3(v, base+1, pTab->zName, 0);
  1663   1798       sqlite3ChangeCookie(db, v, pTab->iDb);
  1664         -    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
  1665   1799       if( !isView ){
         1800  +/*
  1666   1801         sqlite3VdbeAddOp(v, OP_Destroy, pTab->tnum, pTab->iDb);
  1667   1802         for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
  1668   1803           sqlite3VdbeAddOp(v, OP_Destroy, pIdx->tnum, pIdx->iDb);
  1669   1804         }
         1805  +*/
         1806  +      destroyTable(v, pTab);
  1670   1807       }
         1808  +    sqlite3VdbeAddOp(v, OP_Close, 0, 0);
  1671   1809       sqlite3VdbeOp3(v, OP_DropTable, pTab->iDb, 0, pTab->zName, 0);
  1672   1810     }
  1673   1811     sqliteViewResetAll(db, iDb);
  1674   1812   
  1675   1813   exit_drop_table:
  1676   1814     sqlite3SrcListDelete(pName);
  1677   1815   }
................................................................................
  2233   2371       int base;
  2234   2372   
  2235   2373       sqlite3BeginWriteOperation(pParse, 0, pIndex->iDb);
  2236   2374       sqlite3OpenMasterTable(v, pIndex->iDb);
  2237   2375       base = sqlite3VdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
  2238   2376       sqlite3VdbeChangeP3(v, base+1, pIndex->zName, 0);
  2239   2377       sqlite3ChangeCookie(db, v, pIndex->iDb);
         2378  +    /* sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb); */
         2379  +    destroyRootPage(v, pIndex->tnum, pIndex->iDb);
  2240   2380       sqlite3VdbeAddOp(v, OP_Close, 0, 0);
  2241         -    sqlite3VdbeAddOp(v, OP_Destroy, pIndex->tnum, pIndex->iDb);
  2242   2381       sqlite3VdbeOp3(v, OP_DropIndex, pIndex->iDb, 0, pIndex->zName, 0);
  2243   2382     }
  2244   2383   
  2245   2384   exit_drop_index:
  2246   2385     sqlite3SrcListDelete(pName);
  2247   2386   }
  2248   2387   

Changes to src/pager.c.

    14     14   ** The pager is used to access a database disk file.  It implements
    15     15   ** atomic commit and rollback through the use of a journal file that
    16     16   ** is separate from the database file.  The pager also implements file
    17     17   ** locking to prevent two processes from writing the same database
    18     18   ** file simultaneously, or one process from reading the database while
    19     19   ** another is writing.
    20     20   **
    21         -** @(#) $Id: pager.c,v 1.171 2004/11/03 08:44:06 danielk1977 Exp $
           21  +** @(#) $Id: pager.c,v 1.172 2004/11/04 14:30:05 danielk1977 Exp $
    22     22   */
    23     23   #include "sqliteInt.h"
    24     24   #include "os.h"
    25     25   #include "pager.h"
    26     26   #include <assert.h>
    27     27   #include <string.h>
    28     28   
................................................................................
  2584   2584   
  2585   2585     /* Mark the page as dirty.  If the page has already been written
  2586   2586     ** to the journal then we can return right away.
  2587   2587     */
  2588   2588     pPg->dirty = 1;
  2589   2589     if( pPg->inJournal && (pPg->inStmt || pPager->stmtInUse==0) ){
  2590   2590       pPager->dirtyCache = 1;
  2591         -    return SQLITE_OK;
  2592         -  }
  2593         -
  2594         -  /* If we get this far, it means that the page needs to be
  2595         -  ** written to the transaction journal or the ckeckpoint journal
  2596         -  ** or both.
  2597         -  **
  2598         -  ** First check to see that the transaction journal exists and
  2599         -  ** create it if it does not.
  2600         -  */
  2601         -  assert( pPager->state!=PAGER_UNLOCK );
  2602         -  rc = sqlite3pager_begin(pData, 0);
  2603         -  if( rc!=SQLITE_OK ){
  2604         -    return rc;
  2605         -  }
  2606         -  assert( pPager->state>=PAGER_RESERVED );
  2607         -  if( !pPager->journalOpen && pPager->useJournal ){
  2608         -    rc = pager_open_journal(pPager);
  2609         -    if( rc!=SQLITE_OK ) return rc;
  2610         -  }
  2611         -  assert( pPager->journalOpen || !pPager->useJournal );
  2612         -  pPager->dirtyCache = 1;
  2613         -
  2614         -  /* The transaction journal now exists and we have a RESERVED or an
  2615         -  ** EXCLUSIVE lock on the main database file.  Write the current page to
  2616         -  ** the transaction journal if it is not there already.
  2617         -  */
  2618         -  if( !pPg->inJournal && (pPager->useJournal || MEMDB) ){
  2619         -    if( (int)pPg->pgno <= pPager->origDbSize ){
  2620         -      int szPg;
  2621         -      u32 saved;
         2591  +  }else{
         2592  +
         2593  +    /* If we get this far, it means that the page needs to be
         2594  +    ** written to the transaction journal or the ckeckpoint journal
         2595  +    ** or both.
         2596  +    **
         2597  +    ** First check to see that the transaction journal exists and
         2598  +    ** create it if it does not.
         2599  +    */
         2600  +    assert( pPager->state!=PAGER_UNLOCK );
         2601  +    rc = sqlite3pager_begin(pData, 0);
         2602  +    if( rc!=SQLITE_OK ){
         2603  +      return rc;
         2604  +    }
         2605  +    assert( pPager->state>=PAGER_RESERVED );
         2606  +    if( !pPager->journalOpen && pPager->useJournal ){
         2607  +      rc = pager_open_journal(pPager);
         2608  +      if( rc!=SQLITE_OK ) return rc;
         2609  +    }
         2610  +    assert( pPager->journalOpen || !pPager->useJournal );
         2611  +    pPager->dirtyCache = 1;
         2612  +  
         2613  +    /* The transaction journal now exists and we have a RESERVED or an
         2614  +    ** EXCLUSIVE lock on the main database file.  Write the current page to
         2615  +    ** the transaction journal if it is not there already.
         2616  +    */
         2617  +    if( !pPg->inJournal && (pPager->useJournal || MEMDB) ){
         2618  +      if( (int)pPg->pgno <= pPager->origDbSize ){
         2619  +        int szPg;
         2620  +        u32 saved;
         2621  +        if( MEMDB ){
         2622  +          PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
         2623  +          TRACE3("JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
         2624  +          assert( pHist->pOrig==0 );
         2625  +          pHist->pOrig = sqliteMallocRaw( pPager->pageSize );
         2626  +          if( pHist->pOrig ){
         2627  +            memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
         2628  +          }
         2629  +        }else{
         2630  +          u32 cksum;
         2631  +          CODEC(pPager, pData, pPg->pgno, 7);
         2632  +          cksum = pager_cksum(pPager, pPg->pgno, pData);
         2633  +          saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
         2634  +          store32bits(cksum, pPg, pPager->pageSize);
         2635  +          szPg = pPager->pageSize+8;
         2636  +          store32bits(pPg->pgno, pPg, -4);
         2637  +          rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
         2638  +          pPager->journalOff += szPg;
         2639  +          TRACE4("JOURNAL %d page %d needSync=%d\n",
         2640  +                  pPager->fd.h, pPg->pgno, pPg->needSync);
         2641  +          CODEC(pPager, pData, pPg->pgno, 0);
         2642  +          *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved;
         2643  +          if( rc!=SQLITE_OK ){
         2644  +            sqlite3pager_rollback(pPager);
         2645  +            pPager->errMask |= PAGER_ERR_FULL;
         2646  +            return rc;
         2647  +          }
         2648  +          pPager->nRec++;
         2649  +          assert( pPager->aInJournal!=0 );
         2650  +          pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
         2651  +          pPg->needSync = !pPager->noSync;
         2652  +          if( pPager->stmtInUse ){
         2653  +            pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
         2654  +            page_add_to_stmt_list(pPg);
         2655  +          }
         2656  +        }
         2657  +      }else{
         2658  +        pPg->needSync = !pPager->journalStarted && !pPager->noSync;
         2659  +        TRACE4("APPEND %d page %d needSync=%d\n",
         2660  +                pPager->fd.h, pPg->pgno, pPg->needSync);
         2661  +      }
         2662  +      if( pPg->needSync ){
         2663  +        pPager->needSync = 1;
         2664  +      }
         2665  +      pPg->inJournal = 1;
         2666  +    }
         2667  +  
         2668  +    /* If the statement journal is open and the page is not in it,
         2669  +    ** then write the current page to the statement journal.  Note that
         2670  +    ** the statement journal format differs from the standard journal format
         2671  +    ** in that it omits the checksums and the header.
         2672  +    */
         2673  +    if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
         2674  +      assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
  2622   2675         if( MEMDB ){
  2623   2676           PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
  2624         -        TRACE3("JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
  2625         -        assert( pHist->pOrig==0 );
  2626         -        pHist->pOrig = sqliteMallocRaw( pPager->pageSize );
  2627         -        if( pHist->pOrig ){
  2628         -          memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
         2677  +        assert( pHist->pStmt==0 );
         2678  +        pHist->pStmt = sqliteMallocRaw( pPager->pageSize );
         2679  +        if( pHist->pStmt ){
         2680  +          memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize);
  2629   2681           }
         2682  +        TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
  2630   2683         }else{
  2631         -        u32 cksum;
         2684  +        store32bits(pPg->pgno, pPg, -4);
  2632   2685           CODEC(pPager, pData, pPg->pgno, 7);
  2633         -        cksum = pager_cksum(pPager, pPg->pgno, pData);
  2634         -        saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
  2635         -        store32bits(cksum, pPg, pPager->pageSize);
  2636         -        szPg = pPager->pageSize+8;
  2637         -        store32bits(pPg->pgno, pPg, -4);
  2638         -        rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
  2639         -        pPager->journalOff += szPg;
  2640         -        TRACE4("JOURNAL %d page %d needSync=%d\n",
  2641         -                pPager->fd.h, pPg->pgno, pPg->needSync);
         2686  +        rc = sqlite3OsWrite(&pPager->stfd,((char*)pData)-4, pPager->pageSize+4);
         2687  +        TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
  2642   2688           CODEC(pPager, pData, pPg->pgno, 0);
  2643         -        *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved;
  2644   2689           if( rc!=SQLITE_OK ){
  2645   2690             sqlite3pager_rollback(pPager);
  2646   2691             pPager->errMask |= PAGER_ERR_FULL;
  2647   2692             return rc;
  2648   2693           }
  2649         -        pPager->nRec++;
  2650         -        assert( pPager->aInJournal!=0 );
  2651         -        pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
  2652         -        pPg->needSync = !pPager->noSync;
  2653         -        if( pPager->stmtInUse ){
  2654         -          pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
  2655         -          page_add_to_stmt_list(pPg);
  2656         -        }
         2694  +        pPager->stmtNRec++;
         2695  +        assert( pPager->aInStmt!=0 );
         2696  +        pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
  2657   2697         }
  2658         -    }else{
  2659         -      pPg->needSync = !pPager->journalStarted && !pPager->noSync;
  2660         -      TRACE4("APPEND %d page %d needSync=%d\n",
  2661         -              pPager->fd.h, pPg->pgno, pPg->needSync);
         2698  +      page_add_to_stmt_list(pPg);
  2662   2699       }
  2663         -    if( pPg->needSync ){
  2664         -      pPager->needSync = 1;
  2665         -    }
  2666         -    pPg->inJournal = 1;
  2667         -  }
  2668         -
  2669         -  /* If the statement journal is open and the page is not in it,
  2670         -  ** then write the current page to the statement journal.  Note that
  2671         -  ** the statement journal format differs from the standard journal format
  2672         -  ** in that it omits the checksums and the header.
  2673         -  */
  2674         -  if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
  2675         -    assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
  2676         -    if( MEMDB ){
  2677         -      PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
  2678         -      assert( pHist->pStmt==0 );
  2679         -      pHist->pStmt = sqliteMallocRaw( pPager->pageSize );
  2680         -      if( pHist->pStmt ){
  2681         -        memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize);
  2682         -      }
  2683         -      TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
  2684         -    }else{
  2685         -      store32bits(pPg->pgno, pPg, -4);
  2686         -      CODEC(pPager, pData, pPg->pgno, 7);
  2687         -      rc = sqlite3OsWrite(&pPager->stfd, ((char*)pData)-4, pPager->pageSize+4);
  2688         -      TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
  2689         -      CODEC(pPager, pData, pPg->pgno, 0);
  2690         -      if( rc!=SQLITE_OK ){
  2691         -        sqlite3pager_rollback(pPager);
  2692         -        pPager->errMask |= PAGER_ERR_FULL;
  2693         -        return rc;
  2694         -      }
  2695         -      pPager->stmtNRec++;
  2696         -      assert( pPager->aInStmt!=0 );
  2697         -      pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
  2698         -    }
  2699         -    page_add_to_stmt_list(pPg);
  2700   2700     }
  2701   2701   
  2702   2702     /* Update the database size and return.
  2703   2703     */
  2704   2704     if( pPager->dbSize<(int)pPg->pgno ){
  2705   2705       pPager->dbSize = pPg->pgno;
  2706   2706       if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){

Changes to src/sqliteInt.h.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Internal interface definitions for SQLite.
    13     13   **
    14         -** @(#) $Id: sqliteInt.h,v 1.329 2004/10/31 02:22:49 drh Exp $
           14  +** @(#) $Id: sqliteInt.h,v 1.330 2004/11/04 14:30:05 danielk1977 Exp $
    15     15   */
    16     16   #ifndef _SQLITEINT_H_
    17     17   #define _SQLITEINT_H_
    18     18   
    19     19   /*
    20     20   ** These #defines should enable >2GB file support on Posix if the
    21     21   ** underlying operating system supports it.  If the OS lacks
................................................................................
  1428   1428   const void *sqlite3ValueText(sqlite3_value*, u8);
  1429   1429   int sqlite3ValueBytes(sqlite3_value*, u8);
  1430   1430   void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
  1431   1431   void sqlite3ValueFree(sqlite3_value*);
  1432   1432   sqlite3_value *sqlite3ValueNew();
  1433   1433   sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
  1434   1434   extern const unsigned char sqlite3UpperToLower[];
         1435  +void sqlite3RootPageMoved(Db*, int, int);
  1435   1436   
  1436   1437   #endif

Changes to src/test3.c.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Code for testing the btree.c module in SQLite.  This code
    13     13   ** is not included in the SQLite library.  It is used for automated
    14     14   ** testing of the SQLite library.
    15     15   **
    16         -** $Id: test3.c,v 1.53 2004/10/31 02:22:49 drh Exp $
           16  +** $Id: test3.c,v 1.54 2004/11/04 14:30:06 danielk1977 Exp $
    17     17   */
    18     18   #include "sqliteInt.h"
    19     19   #include "pager.h"
    20     20   #include "btree.h"
    21     21   #include "tcl.h"
    22     22   #include <stdlib.h>
    23     23   #include <string.h>
................................................................................
   318    318     if( argc!=3 ){
   319    319       Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
   320    320          " ID TABLENUM\"", 0);
   321    321       return TCL_ERROR;
   322    322     }
   323    323     pBt = sqlite3TextToPtr(argv[1]);
   324    324     if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
   325         -  rc = sqlite3BtreeDropTable(pBt, iTable);
          325  +  rc = sqlite3BtreeDropTable(pBt, iTable, 0);
   326    326     if( rc!=SQLITE_OK ){
   327    327       Tcl_AppendResult(interp, errorName(rc), 0);
   328    328       return TCL_ERROR;
   329    329     }
   330    330     return TCL_OK;
   331    331   }
   332    332   

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.422 2004/11/03 16:27:01 drh Exp $
           46  +** $Id: vdbe.c,v 1.423 2004/11/04 14:30:06 danielk1977 Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include "os.h"
    50     50   #include <ctype.h>
    51     51   #include "vdbeInt.h"
    52     52   
    53     53   /*
................................................................................
  3606   3606   ** The table being destroyed is in the main database file if P2==0.  If
  3607   3607   ** P2==1 then the table to be clear is in the auxiliary database file
  3608   3608   ** that is used to store tables create using CREATE TEMPORARY TABLE.
  3609   3609   **
  3610   3610   ** See also: Clear
  3611   3611   */
  3612   3612   case OP_Destroy: {
  3613         -  rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1);
         3613  +  int iMoved;
         3614  +  rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved);
         3615  +#ifndef SQLITE_OMIT_AUTOVACUUM
         3616  +  pTos++;
         3617  +  pTos->flags = MEM_Int;
         3618  +  pTos->i = iMoved;
         3619  +  if( iMoved!=0 ){
         3620  +    sqlite3RootPageMoved(&db->aDb[pOp->p2], iMoved, pOp->p1);
         3621  +  }
         3622  +#endif
  3614   3623     break;
  3615   3624   }
  3616   3625   
  3617   3626   /* Opcode: Clear P1 P2 *
  3618   3627   **
  3619   3628   ** Delete all contents of the database table or index whose root page
  3620   3629   ** in the database file is given by P1.  But, unlike Destroy, do not

Changes to test/autovacuum.test.

     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this file is testing the SELECT statement.
    13     13   #
    14         -# $Id: autovacuum.test,v 1.5 2004/11/04 02:57:35 danielk1977 Exp $
           14  +# $Id: autovacuum.test,v 1.6 2004/11/04 14:30:06 danielk1977 Exp $
    15     15   
    16     16   set testdir [file dirname $argv0]
    17     17   source $testdir/tester.tcl
    18     18   
    19     19   # Return a string $len characters long. The returned string is $char repeated
    20     20   # over and over. For example, [make_str abc 8] returns "abcabcab".
    21     21   proc make_str {char len} {
................................................................................
   139    139   
   140    140     do_test autovacuum-2.$i.4 {
   141    141       execsql {
   142    142         pragma integrity_check
   143    143       }
   144    144     } {ok}
   145    145   }
   146         -
   147    146   
   148    147   finish_test
   149    148