/ Check-in [6afe467d]
Login

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

Overview
Comment:Make sure the database file is correctly truncated after a ROLLBACK that occurs after a statement abort. (CVS 1893)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6afe467d146828d67ad17af21604c2e691aa5dff
User & Date: drh 2004-08-18 19:09:44
Context
2004-08-19
13:29
Add the SQLITE_BUSY_RESERVED_LOCK compile-time option. (CVS 1894) check-in: 25fe7a42 user: drh tags: trunk
2004-08-18
19:09
Make sure the database file is correctly truncated after a ROLLBACK that occurs after a statement abort. (CVS 1893) check-in: 6afe467d user: drh tags: trunk
16:05
Better debug logging of the pager. (CVS 1892) check-in: 1cc0323f user: drh 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.157 2004/08/18 16:05:19 drh Exp $
           21  +** @(#) $Id: pager.c,v 1.158 2004/08/18 19:09:44 drh Exp $
    22     22   */
    23     23   #include "os.h"         /* Must be first to enable large file support */
    24     24   #include "sqliteInt.h"
    25     25   #include "pager.h"
    26     26   #include <assert.h>
    27     27   #include <string.h>
    28     28   
................................................................................
  1012   1012         }
  1013   1013       }
  1014   1014       pPg->needSync = 0;
  1015   1015       pPg->dirty = 0;
  1016   1016     }
  1017   1017     return rc;
  1018   1018   }
         1019  +
         1020  +/*
         1021  +** Truncate the main file of the given pager to the number of pages
         1022  +** indicated.
         1023  +*/
         1024  +static int pager_truncate(Pager *pPager, int nPage){
         1025  +  return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(off_t)nPage);
         1026  +}
  1019   1027   
  1020   1028   /*
  1021   1029   ** Playback the journal and thus restore the database file to
  1022   1030   ** the state it was in before we started making changes.  
  1023   1031   **
  1024   1032   ** The journal file format is as follows: 
  1025   1033   **
................................................................................
  1131   1139       }
  1132   1140   
  1133   1141       /* If this is the first header read from the journal, truncate the
  1134   1142       ** database file back to it's original size.
  1135   1143       */
  1136   1144       if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
  1137   1145         assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg );
  1138         -      rc = sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(off_t)mxPg);
         1146  +      rc = pager_truncate(pPager, mxPg);
  1139   1147         if( rc!=SQLITE_OK ){
  1140   1148           goto end_playback;
  1141   1149         }
  1142   1150         pPager->dbSize = mxPg;
  1143   1151       }
  1144   1152   
  1145   1153       /* rc = sqlite3OsSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */
................................................................................
  1231   1239     if( !hdrOff ){
  1232   1240       hdrOff = szJ;
  1233   1241     }
  1234   1242     
  1235   1243   
  1236   1244     /* Truncate the database back to its original size.
  1237   1245     */
  1238         -  rc = sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(off_t)pPager->stmtSize);
         1246  +  rc = pager_truncate(pPager, pPager->stmtSize);
  1239   1247     pPager->dbSize = pPager->stmtSize;
  1240   1248   
  1241   1249     /* Figure out how many records are in the statement journal.
  1242   1250     */
  1243   1251     assert( pPager->stmtInUse && pPager->journalOpen );
  1244   1252     sqlite3OsSeek(&pPager->stfd, 0);
  1245   1253     nRec = pPager->stmtNRec;
................................................................................
  1669   1677       memoryTruncate(pPager);
  1670   1678       return SQLITE_OK;
  1671   1679     }
  1672   1680     rc = syncJournal(pPager);
  1673   1681     if( rc!=SQLITE_OK ){
  1674   1682       return rc;
  1675   1683     }
  1676         -  rc = sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(off_t)nPage);
         1684  +  rc = pager_truncate(pPager, nPage);
  1677   1685     if( rc==SQLITE_OK ){
  1678   1686       pPager->dbSize = nPage;
  1679   1687     }
  1680   1688     return rc;
  1681   1689   }
  1682   1690   
  1683   1691   /*
................................................................................
  2856   2864     if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){
  2857   2865       if( pPager->state>=PAGER_EXCLUSIVE ){
  2858   2866         pager_playback(pPager);
  2859   2867       }
  2860   2868       return pager_errcode(pPager);
  2861   2869     }
  2862   2870     if( pPager->state==PAGER_RESERVED ){
  2863         -    int rc2;
         2871  +    int rc2, rc3;
  2864   2872       rc = pager_reload_cache(pPager);
  2865         -    rc2 = pager_unwritelock(pPager);
         2873  +    rc2 = pager_truncate(pPager, pPager->origDbSize);
         2874  +    rc3 = pager_unwritelock(pPager);
  2866   2875       if( rc==SQLITE_OK ){
  2867   2876         rc = rc2;
         2877  +      if( rc3 ) rc = rc3;
  2868   2878       }
  2869   2879     }else{
  2870   2880       rc = pager_playback(pPager);
  2871   2881     }
  2872   2882     if( rc!=SQLITE_OK ){
  2873   2883       rc = SQLITE_CORRUPT;
  2874   2884       pPager->errMask |= PAGER_ERR_CORRUPT;

Added test/pager3.test.

            1  +# 2001 September 15
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.  The
           12  +# focus of this script is page cache subsystem.
           13  +#
           14  +# $Id: pager3.test,v 1.1 2004/08/18 19:09:44 drh Exp $
           15  +
           16  +
           17  +set testdir [file dirname $argv0]
           18  +source $testdir/tester.tcl
           19  +
           20  +# This test makes sure the database file is truncated back to the correct
           21  +# length on a rollback.
           22  +#
           23  +# After some preliminary setup, a transaction is start at NOTE (1).
           24  +# The create table on the following line allocates an additional page
           25  +# at the end of the database file.  But that page is not written because
           26  +# the database still has a RESERVED lock, not an EXCLUSIVE lock.  The
           27  +# new page is held in memory and the size of the file is unchanged.
           28  +# The insert at NOTE (2) begins adding additional pages.  Then it hits
           29  +# a constraint error and aborts.  The abort causes sqlite3OsTruncate()
           30  +# to be called to restore the file to the same length as it was after
           31  +# the create table.  But the create table results had not yet been
           32  +# written so the file is actually lengthened by this truncate.  Finally,
           33  +# the rollback at NOTE (3) is called to undo all the changes since the
           34  +# begin.  This rollback should truncate the database again.
           35  +# 
           36  +# This test was added because the second truncate at NOTE (3) was not
           37  +# occurring on early versions of SQLite 3.0.
           38  +#
           39  +do_test pager3-1.1 {
           40  +  execsql {
           41  +    create table t1(a unique, b);
           42  +    insert into t1 values(1, 'abcdefghijklmnopqrstuvwxyz');
           43  +    insert into t1 values(2, 'abcdefghijklmnopqrstuvwxyz');
           44  +    update t1 set b=b||a||b;
           45  +    update t1 set b=b||a||b;
           46  +    update t1 set b=b||a||b;
           47  +    update t1 set b=b||a||b;
           48  +    update t1 set b=b||a||b;
           49  +    update t1 set b=b||a||b;
           50  +    create temp table t2 as select * from t1;
           51  +    begin;                  ------- NOTE (1)
           52  +    create table t3(x);
           53  +  }
           54  +  catchsql {
           55  +    insert into t1 select 4-a, b from t2;  ----- NOTE (2)
           56  +  }
           57  +  execsql {
           58  +    rollback;  ------- NOTE (3)
           59  +  }
           60  +  db close
           61  +  sqlite3 db test.db
           62  +  execsql {
           63  +    pragma integrity_check;
           64  +  }
           65  +} ok
           66  +
           67  +
           68  +finish_test