SQLite

Check-in [6afe467d14]
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
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6afe467d146828d67ad17af21604c2e691aa5dff
User & Date: drh 2004-08-18 19:09:44.000
Context
2004-08-19
13:29
Add the SQLITE_BUSY_RESERVED_LOCK compile-time option. (CVS 1894) (check-in: 25fe7a42ec 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: 6afe467d14 user: drh tags: trunk)
16:05
Better debug logging of the pager. (CVS 1892) (check-in: 1cc0323f25 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** 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.157 2004/08/18 16:05:19 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>








|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** 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.158 2004/08/18 19:09:44 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

1012
1013
1014
1015
1016
1017
1018








1019
1020
1021
1022
1023
1024
1025
      }
    }
    pPg->needSync = 0;
    pPg->dirty = 0;
  }
  return rc;
}









/*
** Playback the journal and thus restore the database file to
** the state it was in before we started making changes.  
**
** The journal file format is as follows: 
**







>
>
>
>
>
>
>
>







1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
      }
    }
    pPg->needSync = 0;
    pPg->dirty = 0;
  }
  return rc;
}

/*
** Truncate the main file of the given pager to the number of pages
** indicated.
*/
static int pager_truncate(Pager *pPager, int nPage){
  return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(off_t)nPage);
}

/*
** Playback the journal and thus restore the database file to
** the state it was in before we started making changes.  
**
** The journal file format is as follows: 
**
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
    }

    /* If this is the first header read from the journal, truncate the
    ** database file back to it's original size.
    */
    if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
      assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg );
      rc = sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(off_t)mxPg);
      if( rc!=SQLITE_OK ){
        goto end_playback;
      }
      pPager->dbSize = mxPg;
    }

    /* rc = sqlite3OsSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */







|







1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
    }

    /* If this is the first header read from the journal, truncate the
    ** database file back to it's original size.
    */
    if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
      assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg );
      rc = pager_truncate(pPager, mxPg);
      if( rc!=SQLITE_OK ){
        goto end_playback;
      }
      pPager->dbSize = mxPg;
    }

    /* rc = sqlite3OsSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
  if( !hdrOff ){
    hdrOff = szJ;
  }
  

  /* Truncate the database back to its original size.
  */
  rc = sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(off_t)pPager->stmtSize);
  pPager->dbSize = pPager->stmtSize;

  /* Figure out how many records are in the statement journal.
  */
  assert( pPager->stmtInUse && pPager->journalOpen );
  sqlite3OsSeek(&pPager->stfd, 0);
  nRec = pPager->stmtNRec;







|







1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
  if( !hdrOff ){
    hdrOff = szJ;
  }
  

  /* Truncate the database back to its original size.
  */
  rc = pager_truncate(pPager, pPager->stmtSize);
  pPager->dbSize = pPager->stmtSize;

  /* Figure out how many records are in the statement journal.
  */
  assert( pPager->stmtInUse && pPager->journalOpen );
  sqlite3OsSeek(&pPager->stfd, 0);
  nRec = pPager->stmtNRec;
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
    memoryTruncate(pPager);
    return SQLITE_OK;
  }
  rc = syncJournal(pPager);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  rc = sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(off_t)nPage);
  if( rc==SQLITE_OK ){
    pPager->dbSize = nPage;
  }
  return rc;
}

/*







|







1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
    memoryTruncate(pPager);
    return SQLITE_OK;
  }
  rc = syncJournal(pPager);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  rc = pager_truncate(pPager, nPage);
  if( rc==SQLITE_OK ){
    pPager->dbSize = nPage;
  }
  return rc;
}

/*
2856
2857
2858
2859
2860
2861
2862
2863
2864

2865
2866
2867

2868
2869
2870
2871
2872
2873
2874
  if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){
    if( pPager->state>=PAGER_EXCLUSIVE ){
      pager_playback(pPager);
    }
    return pager_errcode(pPager);
  }
  if( pPager->state==PAGER_RESERVED ){
    int rc2;
    rc = pager_reload_cache(pPager);

    rc2 = pager_unwritelock(pPager);
    if( rc==SQLITE_OK ){
      rc = rc2;

    }
  }else{
    rc = pager_playback(pPager);
  }
  if( rc!=SQLITE_OK ){
    rc = SQLITE_CORRUPT;
    pPager->errMask |= PAGER_ERR_CORRUPT;







|

>
|


>







2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
  if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){
    if( pPager->state>=PAGER_EXCLUSIVE ){
      pager_playback(pPager);
    }
    return pager_errcode(pPager);
  }
  if( pPager->state==PAGER_RESERVED ){
    int rc2, rc3;
    rc = pager_reload_cache(pPager);
    rc2 = pager_truncate(pPager, pPager->origDbSize);
    rc3 = pager_unwritelock(pPager);
    if( rc==SQLITE_OK ){
      rc = rc2;
      if( rc3 ) rc = rc3;
    }
  }else{
    rc = pager_playback(pPager);
  }
  if( rc!=SQLITE_OK ){
    rc = SQLITE_CORRUPT;
    pPager->errMask |= PAGER_ERR_CORRUPT;
Added test/pager3.test.








































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 2001 September 15
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is page cache subsystem.
#
# $Id: pager3.test,v 1.1 2004/08/18 19:09:44 drh Exp $


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

# This test makes sure the database file is truncated back to the correct
# length on a rollback.
#
# After some preliminary setup, a transaction is start at NOTE (1).
# The create table on the following line allocates an additional page
# at the end of the database file.  But that page is not written because
# the database still has a RESERVED lock, not an EXCLUSIVE lock.  The
# new page is held in memory and the size of the file is unchanged.
# The insert at NOTE (2) begins adding additional pages.  Then it hits
# a constraint error and aborts.  The abort causes sqlite3OsTruncate()
# to be called to restore the file to the same length as it was after
# the create table.  But the create table results had not yet been
# written so the file is actually lengthened by this truncate.  Finally,
# the rollback at NOTE (3) is called to undo all the changes since the
# begin.  This rollback should truncate the database again.
# 
# This test was added because the second truncate at NOTE (3) was not
# occurring on early versions of SQLite 3.0.
#
do_test pager3-1.1 {
  execsql {
    create table t1(a unique, b);
    insert into t1 values(1, 'abcdefghijklmnopqrstuvwxyz');
    insert into t1 values(2, 'abcdefghijklmnopqrstuvwxyz');
    update t1 set b=b||a||b;
    update t1 set b=b||a||b;
    update t1 set b=b||a||b;
    update t1 set b=b||a||b;
    update t1 set b=b||a||b;
    update t1 set b=b||a||b;
    create temp table t2 as select * from t1;
    begin;                  ------- NOTE (1)
    create table t3(x);
  }
  catchsql {
    insert into t1 select 4-a, b from t2;  ----- NOTE (2)
  }
  execsql {
    rollback;  ------- NOTE (3)
  }
  db close
  sqlite3 db test.db
  execsql {
    pragma integrity_check;
  }
} ok


finish_test