/ 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 Unified Diffs Ignore Whitespace Patch

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
4299
4300
4301
4302
4303
4304
4305

4306
4307





















4308
4309
4310
4311
4312
4313
4314
....
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.535 2009/01/07 02:03:35 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
** moved as part of a database reorganization just before the transaction 
** is being committed. In this case, it is guaranteed that the database page 
** pPg refers to will not be written to again within this transaction.
*/
int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
  PgHdr *pPgOld;  /* The page being overwritten. */
  Pgno needSyncPgno = 0;


  assert( pPg->nRef>0 );






















  PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n", 
      PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno));
  IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno))

  pager_get_content(pPg);

................................................................................
    ** this transaction, it may be written to the database file before
    ** it is synced into the journal file. This way, it may end up in
    ** the journal file twice, but that is not a problem.
    **
    ** The sqlite3PagerGet() call may cause the journal to sync. So make
    ** sure the Pager.needSync flag is set too.
    */
    int rc;
    PgHdr *pPgHdr;
    assert( pPager->needSync );
    rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
    if( rc!=SQLITE_OK ){
      if( pPager->pInJournal && needSyncPgno<=pPager->dbOrigSize ){
        sqlite3BitvecClear(pPager->pInJournal, needSyncPgno);
      }







|







 







>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
....
4383
4384
4385
4386
4387
4388
4389

4390
4391
4392
4393
4394
4395
4396
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.536 2009/01/07 10:35:19 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
** moved as part of a database reorganization just before the transaction 
** is being committed. In this case, it is guaranteed that the database page 
** pPg refers to will not be written to again within this transaction.
*/
int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
  PgHdr *pPgOld;  /* The page being overwritten. */
  Pgno needSyncPgno = 0;
  int rc;

  assert( pPg->nRef>0 );

  /* If the page being moved is dirty and has not been saved by the latest
  ** savepoint, then save the current contents of the page into the 
  ** sub-journal now. This is required to handle the following scenario:
  **
  **   BEGIN;
  **     <journal page X, then modify it in memory>
  **     SAVEPOINT one;
  **       <Move page X to location Y>
  **     ROLLBACK TO one;
  **
  ** If page X were not written to the sub-journal here, it would not
  ** be possible to restore its contents when the "ROLLBACK TO one"
  ** statement were processed.
  */
  if( pPg->flags&PGHDR_DIRTY 
   && subjRequiresPage(pPg)
   && SQLITE_OK!=(rc = subjournalPage(pPg))
  ){
    return rc;
  }

  PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n", 
      PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno));
  IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno))

  pager_get_content(pPg);

................................................................................
    ** this transaction, it may be written to the database file before
    ** it is synced into the journal file. This way, it may end up in
    ** the journal file twice, but that is not a problem.
    **
    ** The sqlite3PagerGet() call may cause the journal to sync. So make
    ** sure the Pager.needSync flag is set too.
    */

    PgHdr *pPgHdr;
    assert( pPager->needSync );
    rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
    if( rc!=SQLITE_OK ){
      if( pPager->pInJournal && needSyncPgno<=pPager->dbOrigSize ){
        sqlite3BitvecClear(pPager->pInJournal, needSyncPgno);
      }

Changes to test/savepoint.test.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
736
737
738
739
740
741
742
743
744
745
746
747





























748
749
750
751
752
753
754
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# $Id: savepoint.test,v 1.9 2009/01/07 08:12:16 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl


#----------------------------------------------------------------------
# The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE
................................................................................
do_test savepoint-11.6 {
  execsql { 
    CREATE TABLE t3(a, b, UNIQUE(a, b));
    ROLLBACK TO one;
  }
} {}
integrity_check savepoint-11.7
do_test savepoint-11.6 {
  execsql { ROLLBACK }
  file size test.db
} {8192}






























#-------------------------------------------------------------------------
# The following tests - savepoint-12.* - test the interaction of 
# savepoints and "ON CONFLICT ROLLBACK" clauses.
# 
do_test savepoint-12.1 {
  execsql {
    CREATE TABLE t4(a PRIMARY KEY, b);







|







 







|




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# $Id: savepoint.test,v 1.10 2009/01/07 10:35:19 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl


#----------------------------------------------------------------------
# The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE
................................................................................
do_test savepoint-11.6 {
  execsql { 
    CREATE TABLE t3(a, b, UNIQUE(a, b));
    ROLLBACK TO one;
  }
} {}
integrity_check savepoint-11.7
do_test savepoint-11.8 {
  execsql { ROLLBACK }
  file size test.db
} {8192}


do_test savepoint-11.9 {
  execsql {
    DROP TABLE IF EXISTS t1;
    DROP TABLE IF EXISTS t2;
    DROP TABLE IF EXISTS t3;
  }
} {}
do_test savepoint-11.10 {
  execsql {
    BEGIN;
      CREATE TABLE t1(a, b);
      CREATE TABLE t2(x, y);
      INSERT INTO t2 VALUES(1, 2);
      SAVEPOINT one;
        INSERT INTO t2 VALUES(3, 4);
        SAVEPOINT two;
          DROP TABLE t1;
        ROLLBACK TO two;
  }
  execsql {SELECT * FROM t2}
} {1 2 3 4}
do_test savepoint-11.11 {
  execsql COMMIT
} {}
do_test savepoint-11.12 {
  execsql {SELECT * FROM t2}
} {1 2 3 4}

#-------------------------------------------------------------------------
# The following tests - savepoint-12.* - test the interaction of 
# savepoints and "ON CONFLICT ROLLBACK" clauses.
# 
do_test savepoint-12.1 {
  execsql {
    CREATE TABLE t4(a PRIMARY KEY, b);