From: dan Date: Thu, 20 Aug 2015 20:25:56 +0000 (+0000) Subject: Fix a problem causing corruption when an UNLOCKED transaction is rolled back. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=699bdf056b62070d2cf5d47b8678ddf4bcb72479;p=thirdparty%2Fsqlite.git Fix a problem causing corruption when an UNLOCKED transaction is rolled back. FossilOrigin-Name: 7c36147846484c96023939864417b5624f3bc5f8 --- diff --git a/manifest b/manifest index 92f5317a3d..ba7247bf36 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\scommitting\san\sunlocked\stransaction,\srelocate\snewly\sallocated\sdatabase\spages\swithin\sthe\sfile\sto\savoid\sconflicting\swith\scommitted\stransactions.\sThere\sare\slots\sof\sthings\sstill\sto\sfix\sin\sthis\scode. -D 2015-08-19T20:27:05.840 +C Fix\sa\sproblem\scausing\scorruption\swhen\san\sUNLOCKED\stransaction\sis\srolled\sback. +D 2015-08-20T20:25:56.029 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 4de3ef40c8b3b75c0c55ff4242a43c8ce1ad90ee F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -315,7 +315,7 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa F src/os_unix.c 388c023582b17890f10c980b30ec1922b471753b F src/os_win.c 40b3af7a47eb1107d0d69e592bec345a3b7b798a F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca -F src/pager.c fe82e368600278cfd35024c20b888e945236f675 +F src/pager.c 48a76f16a75112c9b064e21e1d1ecf0b4d87b5cd F src/pager.h 3fc23bca2e7d606ca4fbdd923713cdcdcec48297 F src/parse.y 199145cd982587d70fa3db2f9b11f7ab118f0acd F src/pcache.c cde06aa50962595e412d497e22fd2e07878ba1f0 @@ -1216,7 +1216,7 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264 F test/unique2.test 41e7f83c6827605991160a31380148a9fc5f1339 F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825 F test/unlocked.test d143a871bd874311d4e5c98ce458218ca6b579fd -F test/unlocked2.test fc4c730a44c3650250467ecacca6ddb969f64405 +F test/unlocked2.test 06a7d5a366bfc6fcaf472a2411f6d45fd9255ed4 F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8 F test/update.test 6c68446b8a0a33d522a7c72b320934596a2d7d32 F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b @@ -1368,7 +1368,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P de1ea450db33b140b11af5b801ea6a15875e774e -R db05422c8fb37e882a7e6cc4bd7c8ffb +P 3bbc31d515ba9fc920c5cbc7059d3eb1ba9c7f8e +R 9ac18b47cee85e97c9fcd4362b958c7d U dan -Z cccfd407eb244cf1cd3b5cab72e65fda +Z 032a41c4b1c95657db216d02c5116d23 diff --git a/manifest.uuid b/manifest.uuid index 7d70f3c411..ce9cb89059 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3bbc31d515ba9fc920c5cbc7059d3eb1ba9c7f8e \ No newline at end of file +7c36147846484c96023939864417b5624f3bc5f8 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index efbea0ab8e..ac2f6bf1a6 100644 --- a/src/pager.c +++ b/src/pager.c @@ -3021,6 +3021,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){ static int pagerRollbackWal(Pager *pPager){ int rc; /* Return Code */ PgHdr *pList; /* List of dirty pages to revert */ + int bPage1 = 0; /* True if page 1 has been undone */ /* For all pages in the cache that are currently dirty or have already ** been written (but not committed) to the log file, do one of the @@ -3034,10 +3035,18 @@ static int pagerRollbackWal(Pager *pPager){ pList = sqlite3PcacheDirtyList(pPager->pPCache); while( pList && rc==SQLITE_OK ){ PgHdr *pNext = pList->pDirty; + if( pList->pgno==1 ) bPage1 = 1; rc = pagerUndoCallback((void *)pPager, pList->pgno); pList = pNext; } + /* If this is an UNLOCKED transaction, then page 1 must be reread from the + ** db file, even if it is not dirty. This is because the b-tree layer may + ** have already zeroed the nFree and iTrunk header fields. */ + if( rc==SQLITE_OK && bPage1==0 && pPager->pAllRead ){ + rc = pagerUndoCallback((void*)pPager, 1); + } + return rc; } diff --git a/test/unlocked2.test b/test/unlocked2.test index f808a84e7b..e9c62194a0 100644 --- a/test/unlocked2.test +++ b/test/unlocked2.test @@ -90,12 +90,72 @@ do_multiclient_test tn { sql2 { INSERT INTO t2 VALUES(randomblob(1500)); } + sql1 COMMIT + } {} + + do_test 2.$tn.3 { sql3 { PRAGMA integrity_check } } {ok} + + do_test 2.$tn.4 { + sql1 { + BEGIN UNLOCKED; + DELETE FROM t1; + } + sql2 { + DELETE FROM t2; + } + sql1 COMMIT + } {} + + do_test 2.$tn.5 { sql3 { PRAGMA integrity_check } } {ok} + + do_test 2.$tn.6 { sql1 { - COMMIT; + INSERT INTO t1 VALUES(randomblob(1500)); + INSERT INTO t1 VALUES(randomblob(1500)); + INSERT INTO t2 VALUES(randomblob(1500)); + DELETE FROM t1 WHERE rowid=1; + } + + sql1 { + BEGIN UNLOCKED; + DELETE FROM t1 WHERE rowid=2; + } + + sql2 { + DELETE FROM t2; } + + sql1 COMMIT } {} - do_test 2.$tn.3 { sql3 { PRAGMA integrity_check } } {ok} + do_test 2.$tn.7 { sql3 { PRAGMA integrity_check } } {ok} } +reset_db +do_execsql_test 3.0 { + PRAGMA journal_mode = wal; + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES(randomblob(1500), randomblob(1500)); + DELETE FROM t1; +} {wal} + +db close +sqlite3 db test.db +breakpoint + +do_execsql_test 3.1 { + BEGIN UNLOCKED; + INSERT INTO t1 VALUES(1, 2); + ROLLBACK; +} + +do_execsql_test 3.2 { + PRAGMA integrity_check; +} {ok} + +do_execsql_test 3.3 { + PRAGMA freelist_count; +} {2} + finish_test +