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: |
6afe467d146828d67ad17af21604c2e6 |
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
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** 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. ** | | | 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 | } /* 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 ); | | | 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 | if( !hdrOff ){ hdrOff = szJ; } /* Truncate the database back to its original size. */ | | | 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 | memoryTruncate(pPager); return SQLITE_OK; } rc = syncJournal(pPager); if( rc!=SQLITE_OK ){ 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 | 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 ){ | | > | > | 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 |