Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -16,11 +16,11 @@ ** 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 $ +** @(#) $Id: pager.c,v 1.536 2009/01/07 10:35:19 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" /* @@ -4301,12 +4301,34 @@ ** 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; + ** + ** SAVEPOINT one; + ** + ** 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)) @@ -4363,11 +4385,10 @@ ** 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 ){ Index: test/savepoint.test ================================================================== --- test/savepoint.test +++ test/savepoint.test @@ -7,11 +7,11 @@ # 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 $ +# $Id: savepoint.test,v 1.10 2009/01/07 10:35:19 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -738,15 +738,44 @@ CREATE TABLE t3(a, b, UNIQUE(a, b)); ROLLBACK TO one; } } {} integrity_check savepoint-11.7 -do_test savepoint-11.6 { +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 {