Improve coverage of pager.c.

FossilOrigin-Name: 2fa05d01b6b11788a5b73d203fcac9d4a4ba9fd8
This commit is contained in:
dan 2010-08-11 18:56:45 +00:00
parent 036391f7f8
commit 22b328b23c
6 changed files with 171 additions and 58 deletions

View File

@ -1,5 +1,5 @@
C Update\san\sr-tree\sextension\stest\scase\sto\saccount\sfor\srecent\schanges\sto\sthe\squery\splanner.\sAlso\sfix\sa\scomment\sin\srtree.c. C Improve\scoverage\sof\spager.c.
D 2010-08-11T12:26:46 D 2010-08-11T18:56:46
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -156,7 +156,7 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e
F src/os_unix.c 11194cbcf6a57456e58022dc537ab8c3497d9bb9 F src/os_unix.c 11194cbcf6a57456e58022dc537ab8c3497d9bb9
F src/os_win.c 51cb62f76262d961ea4249489383d714501315a7 F src/os_win.c 51cb62f76262d961ea4249489383d714501315a7
F src/pager.c b3db762350ee71f5f8bde04f21ca2ffcccded483 F src/pager.c 3fb56c4d03798058e5cf57b668468fa616e20bac
F src/pager.h 80726162dc3942f59ab27b738fb667b9ba0a89d5 F src/pager.h 80726162dc3942f59ab27b738fb667b9ba0a89d5
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07 F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
@ -539,10 +539,10 @@ F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/null.test a8b09b8ed87852742343b33441a9240022108993
F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
F test/pager1.test d8e4b2bc8164c920e6ea0572c9e13576d6e4f3fa F test/pager1.test 20457c96ab1d4e876d335cfd6ddd0f539bda3f81
F test/pager2.test f5c757c271ce642d36a393ecbfb3aef1c240dcef F test/pager2.test 9edc1584cbc8ecd3b34dbcc8e86467bf05caa27f
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
F test/pagerfault.test c1d176326ce244db157ce9c3ba128be2a9b172d6 F test/pagerfault.test 495ab0a0ed30aebe7e4278fcee148986085d4c8b
F test/pagerfault2.test 1f79ea40d1133b2683a2f811b00f2399f7ec2401 F test/pagerfault2.test 1f79ea40d1133b2683a2f811b00f2399f7ec2401
F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806 F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
@ -843,7 +843,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 7c674aaba52b00a78babc1e1ece7e5b652b65039 P eaaca669a4afc83906806b22365b010c83bc3db8
R e8f0a89b3e6e46377528a5271511edf8 R 2966f30f98145ee75718d7c3465c6545
U dan U dan
Z ddfd9f64a4ee25bfe95e56a61185d67f Z cd90e6256916f41a20463762a4c0c757

View File

@ -1 +1 @@
eaaca669a4afc83906806b22365b010c83bc3db8 2fa05d01b6b11788a5b73d203fcac9d4a4ba9fd8

View File

@ -273,10 +273,13 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** **
** ERROR: ** ERROR:
** **
** The ERROR state is entered when an IO, OOM or disk-full error ** The ERROR state is entered when an IO or disk-full error (including
** occurs at a point in the code that makes it difficult to be sure ** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it
** that the in-memory pager state (cache contents, db size etc.) are ** difficult to be sure that the in-memory pager state (cache contents,
** consistent with the contents of the file-system. ** db size etc.) are consistent with the contents of the file-system.
**
** Temporary pager files may enter the ERROR state, but in-memory pagers
** cannot.
** **
** For example, if an IO error occurs while performing a rollback, ** For example, if an IO error occurs while performing a rollback,
** the contents of the page-cache may be left in an inconsistent state. ** the contents of the page-cache may be left in an inconsistent state.
@ -323,6 +326,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** * The Pager.errCode variable is set to something other than SQLITE_OK. ** * The Pager.errCode variable is set to something other than SQLITE_OK.
** * There are one or more outstanding references to pages (after the ** * There are one or more outstanding references to pages (after the
** last reference is dropped the pager should move back to OPEN state). ** last reference is dropped the pager should move back to OPEN state).
** * The pager is not an in-memory pager.
** **
** **
** Notes: ** Notes:
@ -825,8 +829,22 @@ static int assert_pager_state(Pager *p){
assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal ); assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal );
assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) ); assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) );
/* Check that MEMDB implies noSync. */ /* Check that MEMDB implies noSync. And an in-memory journal. Since
assert( !MEMDB || p->noSync ); ** this means an in-memory pager performs no IO at all, it cannot encounter
** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing
** a journal file. (although the in-memory journal implementation may
** return SQLITE_IOERR_NOMEM while the journal file is being written). It
** is therefore not possible for an in-memory pager to enter the ERROR
** state.
*/
if( MEMDB ){
assert( p->noSync );
assert( p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_MEMORY
);
assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN );
assert( pagerUseWal(p)==0 );
}
/* If changeCountDone is set, a RESERVED lock or greater must be held /* If changeCountDone is set, a RESERVED lock or greater must be held
** on the file. ** on the file.
@ -1759,7 +1777,8 @@ static void pager_unlock(Pager *pPager){
** it can safely move back to PAGER_OPEN state. This happens in both ** it can safely move back to PAGER_OPEN state. This happens in both
** normal and exclusive-locking mode. ** normal and exclusive-locking mode.
*/ */
if( pPager->errCode && !MEMDB ){ if( pPager->errCode ){
assert( !MEMDB );
pager_reset(pPager); pager_reset(pPager);
pPager->changeCountDone = pPager->tempFile; pPager->changeCountDone = pPager->tempFile;
pPager->eState = PAGER_OPEN; pPager->eState = PAGER_OPEN;
@ -2567,13 +2586,10 @@ static int pager_playback(Pager *pPager, int isHot){
char *zMaster = 0; /* Name of master journal file if any */ char *zMaster = 0; /* Name of master journal file if any */
int needPagerReset; /* True to reset page prior to first page rollback */ int needPagerReset; /* True to reset page prior to first page rollback */
if( !isOpen(pPager->jfd) ){
return SQLITE_OK;
}
/* Figure out how many records are in the journal. Abort early if /* Figure out how many records are in the journal. Abort early if
** the journal is empty. ** the journal is empty.
*/ */
assert( isOpen(pPager->jfd) );
rc = sqlite3OsFileSize(pPager->jfd, &szJ); rc = sqlite3OsFileSize(pPager->jfd, &szJ);
if( rc!=SQLITE_OK || szJ==0 ){ if( rc!=SQLITE_OK || szJ==0 ){
goto end_playback; goto end_playback;
@ -3341,46 +3357,47 @@ void sqlite3PagerSetBusyhandler(
** then *pPageSize is set to the old, retained page size before returning. ** then *pPageSize is set to the old, retained page size before returning.
*/ */
int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize, int nReserve){ int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize, int nReserve){
int rc = pPager->errCode;
/* It is not possible to do a full assert_pager_state() here, as this /* It is not possible to do a full assert_pager_state() here, as this
** function may be called from within PagerOpen(), before the state ** function may be called from within PagerOpen(), before the state
** of the Pager object is internally consistent. ** of the Pager object is internally consistent.
**
** At one point this function returned an error if the pager was in
** PAGER_ERROR state. But since PAGER_ERROR state guarantees that
** there is at least one outstanding page reference, this function
** is a no-op for that case anyhow.
*/ */
assert( rc==SQLITE_OK || pPager->eState==PAGER_ERROR );
if( rc==SQLITE_OK ){ u16 pageSize = *pPageSize;
u16 pageSize = *pPageSize; assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) );
assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); if( (pPager->memDb==0 || pPager->dbSize==0)
if( (pPager->memDb==0 || pPager->dbSize==0) && sqlite3PcacheRefCount(pPager->pPCache)==0
&& sqlite3PcacheRefCount(pPager->pPCache)==0 && pageSize && pageSize!=pPager->pageSize
&& pageSize && pageSize!=pPager->pageSize ){
){ char *pNew; /* New temp space */
char *pNew; /* New temp space */ i64 nByte = 0;
i64 nByte = 0; if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){
if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){ int rc = sqlite3OsFileSize(pPager->fd, &nByte);
rc = sqlite3OsFileSize(pPager->fd, &nByte); if( rc!=SQLITE_OK ) return rc;
if( rc!=SQLITE_OK ) return rc; }
} pNew = (char *)sqlite3PageMalloc(pageSize);
pNew = (char *)sqlite3PageMalloc(pageSize); if( !pNew ){
if( !pNew ){ return SQLITE_NOMEM;
rc = SQLITE_NOMEM; }else{
}else{ pager_reset(pPager);
pager_reset(pPager); pPager->dbSize = nByte/pageSize;
pPager->dbSize = nByte/pageSize; pPager->pageSize = pageSize;
pPager->pageSize = pageSize; sqlite3PageFree(pPager->pTmpSpace);
sqlite3PageFree(pPager->pTmpSpace); pPager->pTmpSpace = pNew;
pPager->pTmpSpace = pNew; sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
}
} }
*pPageSize = (u16)pPager->pageSize;
if( nReserve<0 ) nReserve = pPager->nReserve;
assert( nReserve>=0 && nReserve<1000 );
pPager->nReserve = (i16)nReserve;
pagerReportSize(pPager);
} }
return rc;
*pPageSize = (u16)pPager->pageSize;
if( nReserve<0 ) nReserve = pPager->nReserve;
assert( nReserve>=0 && nReserve<1000 );
pPager->nReserve = (i16)nReserve;
pagerReportSize(pPager);
return SQLITE_OK;
} }
/* /*
@ -4743,9 +4760,11 @@ int sqlite3PagerSharedLock(Pager *pPager){
** mode. Otherwise, the following function call is a no-op. ** mode. Otherwise, the following function call is a no-op.
*/ */
rc = pagerOpenWalIfPresent(pPager); rc = pagerOpenWalIfPresent(pPager);
assert( pPager->pWal==0 || rc==SQLITE_OK );
} }
if( pagerUseWal(pPager) && rc==SQLITE_OK ){ if( pagerUseWal(pPager) ){
assert( rc==SQLITE_OK );
rc = pagerBeginReadTransaction(pPager); rc = pagerBeginReadTransaction(pPager);
} }
@ -4755,6 +4774,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
failed: failed:
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
assert( !MEMDB );
pager_unlock(pPager); pager_unlock(pPager);
assert( pPager->eState==PAGER_OPEN ); assert( pPager->eState==PAGER_OPEN );
}else{ }else{
@ -5080,7 +5100,7 @@ int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
assert( pPager->eState>=PAGER_READER ); assert( pPager->eState>=PAGER_READER );
pPager->subjInMemory = (u8)subjInMemory; pPager->subjInMemory = (u8)subjInMemory;
if( pPager->eState==PAGER_READER ){ if( ALWAYS(pPager->eState==PAGER_READER) ){
assert( pPager->pInJournal==0 ); assert( pPager->pInJournal==0 );
if( pagerUseWal(pPager) ){ if( pagerUseWal(pPager) ){

View File

@ -1062,6 +1062,10 @@ do_execsql_test pager1-6.8 {
} {11} } {11}
do_execsql_test pager1-6.9 { COMMIT } {} do_execsql_test pager1-6.9 { COMMIT } {}
do_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {10}
do_execsql_test pager1-6.11 { SELECT * FROM t11 } {1 2 3 4}
do_execsql_test pager1-6.12 { PRAGMA max_page_count } {11}
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# The following tests work with "PRAGMA journal_mode=TRUNCATE" and # The following tests work with "PRAGMA journal_mode=TRUNCATE" and
@ -1742,7 +1746,7 @@ do_multiclient_test tn {
} }
} {1 2 3 4 5 6} } {1 2 3 4 5 6}
do_test pager1-17.$tn.3.2 { do_test pager1-17.$tn.3.2 {
csql1 { INSERT INTO t1 VALUES(3, 4) } csql1 { INSERT INTO t1 VALUES(3, 4) }
} {1 {database is locked}} } {1 {database is locked}}
do_test pager1-17.$tn.3.3 { sql2 COMMIT } {} do_test pager1-17.$tn.3.3 { sql2 COMMIT } {}
} }
@ -2232,6 +2236,7 @@ db close
tv delete tv delete
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
#
do_test pager1.27.1 { do_test pager1.27.1 {
faultsim_delete_and_reopen faultsim_delete_and_reopen
sqlite3_pager_refcounts db sqlite3_pager_refcounts db
@ -2243,4 +2248,29 @@ do_test pager1.27.1 {
execsql COMMIT execsql COMMIT
} {} } {}
#-------------------------------------------------------------------------
# Test that attempting to open a write-transaction with
# locking_mode=exclusive in WAL mode fails if there are other clients on
# the same database.
#
catch { db close }
do_multiclient_test tn {
do_test pager1-28.$tn.1 {
sql1 {
PRAGMA journal_mode = WAL;
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES('a', 'b');
}
} {wal}
do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}
do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
do_test pager1-28.$tn.4 {
csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
} {1 {database is locked}}
code2 { db2 close ; sqlite3 db2 test.db }
do_test pager1-28.$tn.4 {
sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
} {}
}
finish_test finish_test

View File

@ -116,4 +116,21 @@ foreach code [list {
db close db close
tv delete tv delete
#-------------------------------------------------------------------------
# Test a ROLLBACK with journal_mode=off.
#
breakpoint
do_test pager2-2.1 {
faultsim_delete_and_reopen
execsql {
CREATE TABLE t1(a, b);
PRAGMA journal_mode = off;
BEGIN;
INSERT INTO t1 VALUES(1, 2);
ROLLBACK;
SELECT * FROM t1;
}
} {off 1 2}
finish_test finish_test

View File

@ -52,7 +52,7 @@ do_faultsim_test pagerfault-1 -prep {
} -body { } -body {
execsql { SELECT count(*) FROM t1 } execsql { SELECT count(*) FROM t1 }
} -test { } -test {
faultsim_test_result {0 4} faultsim_test_result {0 4}
faultsim_integrity_check faultsim_integrity_check
if {[db one { SELECT count(*) FROM t1 }] != 4} { if {[db one { SELECT count(*) FROM t1 }] != 4} {
error "Database content appears incorrect" error "Database content appears incorrect"
@ -1078,4 +1078,50 @@ do_faultsim_test pagerfault-22 -prep {
faultsim_integrity_check faultsim_integrity_check
} }
#-------------------------------------------------------------------------
# Provoke an OOM error during a commit of multi-file transaction. One of
# the databases written during the transaction is an in-memory database.
# This test causes rollback of the in-memory database after CommitPhaseOne()
# has successfully returned. i.e. the series of calls for the aborted commit
# is:
#
# PagerCommitPhaseOne(<in-memory-db>) -> SQLITE_OK
# PagerCommitPhaseOne(<file-db>) -> SQLITE_IOERR
# PagerRollback(<in-memory-db>)
# PagerRollback(<file-db>)
#
do_faultsim_test pagerfault-23 -prep {
foreach f [glob -nocomplain test.db*] { file delete -force $f }
sqlite3 db :memory:
db eval {
ATTACH 'test.db2' AS aux;
CREATE TABLE t1(a, b);
CREATE TABLE aux.t2(a, b);
}
} -body {
execsql {
BEGIN;
INSERT INTO t1 VALUES(1,2);
INSERT INTO t2 VALUES(3,4);
COMMIT;
}
} -test {
faultsim_test_result {0 {}}
faultsim_integrity_check
}
do_faultsim_test pagerfault-24 -prep {
faultsim_delete_and_reopen
db eval { PRAGMA temp_store = file }
execsql { CREATE TABLE x(a, b) }
} -body {
execsql { CREATE TEMP TABLE t1(a, b) }
} -test {
faultsim_test_result {0 {}} {1 {unable to open a temporary database file for storing temporary tables}}
set ic [db eval { PRAGMA temp.integrity_check }]
if {$ic != "ok"} { error "Integrity check: $ic" }
}
finish_test finish_test