/ Check-in [3a4bb832]
Login

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

Overview
Comment:Fix a problem with reverting a 'DROP TABLE' command executed inside of a savepoint on an auto-vacuum database. (CVS 6129)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3a4bb83235e9a79297e7d5d47ac7674c9df960bf
User & Date: danielk1977 2009-01-07 10:35:19
Context
2009-01-07
10:52
Add a comment to the openSubjournal() function in pager.c. (CVS 6130) check-in: 04387ae1 user: danielk1977 tags: trunk
10:35
Fix a problem with reverting a 'DROP TABLE' command executed inside of a savepoint on an auto-vacuum database. (CVS 6129) check-in: 3a4bb832 user: danielk1977 tags: trunk
08:12
Fix savepoint related bugs. A rollback caused by an IO error or "OR ROLLBACK" clause while one or more savepoints were open was leaving the sqlite3 structure in an invalid state. (CVS 6128) check-in: e5d42c69 user: danielk1977 tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

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.535 2009/01/07 02:03:35 drh Exp $
           21  +** @(#) $Id: pager.c,v 1.536 2009/01/07 10:35:19 danielk1977 Exp $
    22     22   */
    23     23   #ifndef SQLITE_OMIT_DISKIO
    24     24   #include "sqliteInt.h"
    25     25   
    26     26   /*
    27     27   ** Macros for troubleshooting.  Normally turned off
    28     28   */
................................................................................
  4299   4299   ** moved as part of a database reorganization just before the transaction 
  4300   4300   ** is being committed. In this case, it is guaranteed that the database page 
  4301   4301   ** pPg refers to will not be written to again within this transaction.
  4302   4302   */
  4303   4303   int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
  4304   4304     PgHdr *pPgOld;  /* The page being overwritten. */
  4305   4305     Pgno needSyncPgno = 0;
         4306  +  int rc;
  4306   4307   
  4307   4308     assert( pPg->nRef>0 );
         4309  +
         4310  +  /* If the page being moved is dirty and has not been saved by the latest
         4311  +  ** savepoint, then save the current contents of the page into the 
         4312  +  ** sub-journal now. This is required to handle the following scenario:
         4313  +  **
         4314  +  **   BEGIN;
         4315  +  **     <journal page X, then modify it in memory>
         4316  +  **     SAVEPOINT one;
         4317  +  **       <Move page X to location Y>
         4318  +  **     ROLLBACK TO one;
         4319  +  **
         4320  +  ** If page X were not written to the sub-journal here, it would not
         4321  +  ** be possible to restore its contents when the "ROLLBACK TO one"
         4322  +  ** statement were processed.
         4323  +  */
         4324  +  if( pPg->flags&PGHDR_DIRTY 
         4325  +   && subjRequiresPage(pPg)
         4326  +   && SQLITE_OK!=(rc = subjournalPage(pPg))
         4327  +  ){
         4328  +    return rc;
         4329  +  }
  4308   4330   
  4309   4331     PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n", 
  4310   4332         PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno));
  4311   4333     IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno))
  4312   4334   
  4313   4335     pager_get_content(pPg);
  4314   4336   
................................................................................
  4361   4383       ** this transaction, it may be written to the database file before
  4362   4384       ** it is synced into the journal file. This way, it may end up in
  4363   4385       ** the journal file twice, but that is not a problem.
  4364   4386       **
  4365   4387       ** The sqlite3PagerGet() call may cause the journal to sync. So make
  4366   4388       ** sure the Pager.needSync flag is set too.
  4367   4389       */
  4368         -    int rc;
  4369   4390       PgHdr *pPgHdr;
  4370   4391       assert( pPager->needSync );
  4371   4392       rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
  4372   4393       if( rc!=SQLITE_OK ){
  4373   4394         if( pPager->pInJournal && needSyncPgno<=pPager->dbOrigSize ){
  4374   4395           sqlite3BitvecClear(pPager->pInJournal, needSyncPgno);
  4375   4396         }

Changes to test/savepoint.test.

     5      5   #
     6      6   #    May you do good and not evil.
     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   #
    12         -# $Id: savepoint.test,v 1.9 2009/01/07 08:12:16 danielk1977 Exp $
           12  +# $Id: savepoint.test,v 1.10 2009/01/07 10:35:19 danielk1977 Exp $
    13     13   
    14     14   set testdir [file dirname $argv0]
    15     15   source $testdir/tester.tcl
    16     16   
    17     17   
    18     18   #----------------------------------------------------------------------
    19     19   # The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE
................................................................................
   736    736   do_test savepoint-11.6 {
   737    737     execsql { 
   738    738       CREATE TABLE t3(a, b, UNIQUE(a, b));
   739    739       ROLLBACK TO one;
   740    740     }
   741    741   } {}
   742    742   integrity_check savepoint-11.7
   743         -do_test savepoint-11.6 {
          743  +do_test savepoint-11.8 {
   744    744     execsql { ROLLBACK }
   745    745     file size test.db
   746    746   } {8192}
   747    747   
          748  +
          749  +do_test savepoint-11.9 {
          750  +  execsql {
          751  +    DROP TABLE IF EXISTS t1;
          752  +    DROP TABLE IF EXISTS t2;
          753  +    DROP TABLE IF EXISTS t3;
          754  +  }
          755  +} {}
          756  +do_test savepoint-11.10 {
          757  +  execsql {
          758  +    BEGIN;
          759  +      CREATE TABLE t1(a, b);
          760  +      CREATE TABLE t2(x, y);
          761  +      INSERT INTO t2 VALUES(1, 2);
          762  +      SAVEPOINT one;
          763  +        INSERT INTO t2 VALUES(3, 4);
          764  +        SAVEPOINT two;
          765  +          DROP TABLE t1;
          766  +        ROLLBACK TO two;
          767  +  }
          768  +  execsql {SELECT * FROM t2}
          769  +} {1 2 3 4}
          770  +do_test savepoint-11.11 {
          771  +  execsql COMMIT
          772  +} {}
          773  +do_test savepoint-11.12 {
          774  +  execsql {SELECT * FROM t2}
          775  +} {1 2 3 4}
          776  +
   748    777   #-------------------------------------------------------------------------
   749    778   # The following tests - savepoint-12.* - test the interaction of 
   750    779   # savepoints and "ON CONFLICT ROLLBACK" clauses.
   751    780   # 
   752    781   do_test savepoint-12.1 {
   753    782     execsql {
   754    783       CREATE TABLE t4(a PRIMARY KEY, b);