From f602963dbc1c8eed4c9fe15b094d97ec74f3825e Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 28 Feb 2012 17:57:34 +0000 Subject: [PATCH] Fix spurious errors that may occur if an empty database is opened and then initialized as a WAL database by a second connection. FossilOrigin-Name: 16330a2f7262173a32ae48a72c0ee2522b6dc554 --- manifest | 15 +++++---- manifest.uuid | 2 +- src/vacuum.c | 20 ++++++----- src/wal.c | 2 +- test/wal8.test | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 17 deletions(-) create mode 100644 test/wal8.test diff --git a/manifest b/manifest index 108aca806a..ffe0e4775e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\scase\swhere\san\serror\scode\swas\sbeing\soverwritten\sin\smultiplexDelete(). -D 2012-02-28T11:52:12.825 +C Fix\sspurious\serrors\sthat\smay\soccur\sif\san\sempty\sdatabase\sis\sopened\sand\sthen\sinitialized\sas\sa\sWAL\sdatabase\sby\sa\ssecond\sconnection. +D 2012-02-28T17:57:34.628 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 3f79a373e57c3b92dabf76f40b065e719d31ac34 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -239,7 +239,7 @@ F src/trigger.c ee7e178fb9188f44b532cebd449a7c1df90fb684 F src/update.c d3076782c887c10e882996550345da9c4c9f9dea F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84 F src/util.c 906731099c4397bf8adf3fa90a833355e7472af0 -F src/vacuum.c 0c0ba2242355c6048d65e2b333abe0f7c06348fa +F src/vacuum.c bfd53f9bd20a8fdb70b0fa8e77182b866875c0d8 F src/vdbe.c 32720e873ed0a23e6ee928b676cd995864b984d6 F src/vdbe.h 18f581cac1f4339ec3299f3e0cc6e11aec654cdb F src/vdbeInt.h 6ff4180a05683566a8835d12f7ec504b22932c82 @@ -250,7 +250,7 @@ F src/vdbemem.c fb0ac964ccbcd94f595eb993c05bfd9c52468a4a F src/vdbesort.c b25814d385895544ebc8118245c8311ded7f81c9 F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843 F src/vtab.c ab90fb600a3f5e4b7c48d22a4cdb2d6b23239847 -F src/wal.c c164c39e8625b2b6e7d7b2aab5e7296ebd7e8190 +F src/wal.c 7bb3ad807afc7973406c805d5157ec7a2f65e146 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/where.c af623942514571895818b9b7ae11db95ae3b3d88 @@ -913,6 +913,7 @@ F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c F test/wal5.test f58ed4b8b542f71c7441da12fbd769d99b362437 F test/wal6.test 2e3bc767d9c2ce35c47106148d43fcbd072a93b3 F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd +F test/wal8.test 5ab217d21f7e5e86af2933a4ffd0d8357cc2c0bd F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe F test/walbak.test b9f68e39646375c2b877be906babcc15d38b4877 F test/walbig.test 0ab8a430ef420a3114f7092e0f30fc9585ffa155 @@ -990,7 +991,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 -P e44e26771e5aa48f3bfa14d6db3e669b5b2a1e73 -R a83bd20b956aa8e93cec00d5fc1e4306 +P c267893a0813beb1764071409025e178318e1ca3 +R 751c4f9505bcae82ab2d498f42151225 U dan -Z a4ff6a0dae74370332c0513312e14191 +Z aacac9f6818b59f3fbe792ef77401913 diff --git a/manifest.uuid b/manifest.uuid index 8a835053fa..df6fdce3ee 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c267893a0813beb1764071409025e178318e1ca3 \ No newline at end of file +16330a2f7262173a32ae48a72c0ee2522b6dc554 \ No newline at end of file diff --git a/src/vacuum.c b/src/vacuum.c index 58a3c9d683..c03b4500b3 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -176,6 +176,18 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ } #endif + rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF"); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + + /* Begin a transaction and take an exclusive lock on the main database + ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below, + ** to ensure that we do not try to change the page-size on a WAL database. + */ + rc = execSql(db, pzErrMsg, "BEGIN;"); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + rc = sqlite3BtreeBeginTrans(pMain, 2); + if( rc!=SQLITE_OK ) goto end_of_vacuum; + /* Do not attempt to change the page size for a WAL database */ if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain)) ==PAGER_JOURNALMODE_WAL ){ @@ -189,20 +201,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ rc = SQLITE_NOMEM; goto end_of_vacuum; } - rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF"); - if( rc!=SQLITE_OK ){ - goto end_of_vacuum; - } #ifndef SQLITE_OMIT_AUTOVACUUM sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac : sqlite3BtreeGetAutoVacuum(pMain)); #endif - /* Begin a transaction */ - rc = execSql(db, pzErrMsg, "BEGIN EXCLUSIVE;"); - if( rc!=SQLITE_OK ) goto end_of_vacuum; - /* Query the schema of the main database. Create a mirror schema ** in the temporary database. */ diff --git a/src/wal.c b/src/wal.c index 97d2185ea2..b077d27d9e 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2397,7 +2397,7 @@ int sqlite3WalRead( iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE; *pInWal = 1; /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */ - return sqlite3OsRead(pWal->pWalFd, pOut, nOut, iOffset); + return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset); } *pInWal = 0; diff --git a/test/wal8.test b/test/wal8.test new file mode 100644 index 0000000000..4b97de7ae7 --- /dev/null +++ b/test/wal8.test @@ -0,0 +1,90 @@ +# 2012 February 28 +# +# 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 file is testing the operation of the library in +# "PRAGMA journal_mode=WAL" mode. +# +# Specifically, it tests the case where a connection opens an empty +# file. Then, another connection opens the same file and initializes +# the connection as a WAL database. Following this, the first connection +# executes a "PRAGMA page_size = XXX" command to set its expected page +# size, and then queries the database. +# +# This is an unusual case, as normally SQLite is able to glean the page +# size from the database file as soon as it is opened (even before the +# first read transaction is executed), and the "PRAGMA page_size = XXX" +# is a no-op. +# +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix wal8 + +db close +forcedelete test.db test.db-wal + +sqlite3 db test.db +sqlite3 db2 test.db + +do_test 1.0 { + execsql { + PRAGMA journal_mode = wal; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + } db2 +} {wal} + +do_catchsql_test 1.1 { + PRAGMA page_size = 4096; + VACUUM; +} {0 {}} + +db close +db2 close +forcedelete test.db test.db-wal + +sqlite3 db test.db +sqlite3 db2 test.db + +do_test 2.0 { + execsql { + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + PRAGMA journal_mode = wal; + } db2 +} {wal} + +do_catchsql_test 2.1 { + PRAGMA page_size = 4096; + VACUUM; +} {0 {}} + +db close +db2 close +forcedelete test.db test.db-wal + +sqlite3 db test.db +sqlite3 db2 test.db + +do_test 3.0 { + execsql { + PRAGMA journal_mode = wal; + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES(1, 2); + } db2 +} {wal} + +do_execsql_test 3.1 { + PRAGMA page_size = 4096; + SELECT name FROM sqlite_master; +} {t1} + +finish_test +