Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -5289,11 +5289,11 @@ ** to drop any locks either. */ if( pPager->dbModified==0 && pPager->exclusiveMode && pPager->journalMode==PAGER_JOURNALMODE_PERSIST ){ - assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ); + assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff ); return SQLITE_OK; } PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); assert( pPager->state==PAGER_SYNCED || MEMDB || !pPager->dbModified ); ADDED test/notify3.test Index: test/notify3.test ================================================================== --- /dev/null +++ test/notify3.test @@ -0,0 +1,73 @@ +# 2010 June 30 +# +# 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 sqlite3_unlock_notify() API. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +set esc [sqlite3_enable_shared_cache 1] + +sqlite3 db test.db +file delete -force test.db2 test.db2-journal test.db2-wal +sqlite3 db2 test.db2 + +do_test notify3-1.1 { + execsql { + CREATE TABLE t1(a, b); + INSERT INTO t1 VALUES('t1 A', 't1 B'); + } +} {} +do_test notify3-1.2 { + execsql { + CREATE TABLE t2(a, b); + INSERT INTO t2 VALUES('t2 A', 't2 B'); + } db2 +} {} + +do_test notify3-1.3 { + execsql { + BEGIN EXCLUSIVE; + INSERT INTO t2 VALUES('t2 C', 't2 D'); + } db2 +} {} +do_test notify3-1.4 { + catchsql { ATTACH 'test.db2' AS aux } +} {0 {}} +do_test notify3-1.5 { + catchsql { SELECT * FROM t2 } +} {1 {database schema is locked: aux}} + +do_test notify3-1.6 { + list [sqlite3_errcode db] [sqlite3_extended_errcode db] +} {SQLITE_LOCKED SQLITE_LOCKED_SHAREDCACHE} + +do_test notify3-1.7 { + sqlite3_extended_result_codes db 1 + catch { set ::stmt [sqlite3_prepare_v2 db "SELECT * FROM t2" -1 tail] } msg + set msg +} {(262) database schema is locked: aux} + +do_test notify3-1.8 { + set ::when 1 + db unlock_notify { set ::res $::when } + set ::when 2 + execsql { COMMIT } db2 + set ::res +} {2} +do_test notify3-1.9 { + catchsql { SELECT * FROM t2 } +} {0 {{t2 A} {t2 B} {t2 C} {t2 D}}} + +sqlite3_enable_shared_cache $esc +finish_test + Index: test/pager1.test ================================================================== --- test/pager1.test +++ test/pager1.test @@ -279,10 +279,12 @@ 12 { PRAGMA synchronous = FULL ; PRAGMA fullfsync = 1 } { } 13 { PRAGMA synchronous = FULL } { testvfs tv -default 1 tv devchar sequential } + 14 { PRAGMA locking_mode = EXCLUSIVE } { + } } { do_test pager1-3.$tn.1 { eval $tcl faultsim_delete_and_reopen db func a_string a_string @@ -1675,8 +1677,86 @@ INSERT INTO t1(aa) VALUES( a_string(100000) ); INSERT INTO t2(aa) VALUES( a_string(100000) ); VACUUM; } } {} + +#------------------------------------------------------------------------- +# Test a couple of special cases that come up while committing +# transactions: +# +# pager1-20.1.*: Committing an in-memory database transaction when the +# database has not been modified at all. +# +# pager1-20.2.*: As above, but with a normal db in exclusive-locking mode. +# +# pager1-20.3.*: Committing a transaction in WAL mode where the database has +# been modified, but all dirty pages have been flushed to +# disk before the commit. +# +do_test pager1-20.1.1 { + catch {db close} + sqlite3 db :memory: + execsql { + CREATE TABLE one(two, three); + INSERT INTO one VALUES('a', 'b'); + } +} {} +do_test pager1-20.1.2 { + execsql { + BEGIN EXCLUSIVE; + COMMIT; + } +} {} + +do_test pager1-20.2.1 { + faultsim_delete_and_reopen + execsql { + PRAGMA locking_mode = exclusive; + PRAGMA journal_mode = persist; + CREATE TABLE one(two, three); + INSERT INTO one VALUES('a', 'b'); + } +} {exclusive persist} +do_test pager1-20.2.2 { + execsql { + BEGIN EXCLUSIVE; + COMMIT; + } +} {} + +do_test pager1-20.3.1 { + faultsim_delete_and_reopen + db func a_string a_string + execsql { + PRAGMA cache_size = 10; + PRAGMA journal_mode = wal; + BEGIN; + CREATE TABLE t1(x); + CREATE TABLE t2(y); + INSERT INTO t1 VALUES(a_string(800)); + INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2 */ + INSERT INTO t1 SELECT a_string(800) FROM t1; /* 4 */ + INSERT INTO t1 SELECT a_string(800) FROM t1; /* 8 */ + INSERT INTO t1 SELECT a_string(800) FROM t1; /* 16 */ + INSERT INTO t1 SELECT a_string(800) FROM t1; /* 32 */ + COMMIT; + } +} {wal} +do_test pager1-20.3.2 { + proc recursive_select {id} { + db eval {SELECT rowid, x FROM t1 WHERE rowid = ($id-1)} { + recursive_select $rowid + } + } + execsql { + BEGIN; + INSERT INTO t2 VALUES('xxxx'); + } + recursive_select 32 + execsql COMMIT +} {} + + finish_test Index: test/pagerfault.test ================================================================== --- test/pagerfault.test +++ test/pagerfault.test @@ -611,10 +611,13 @@ } -body { execsql { CREATE TABLE xx(a, b) } } -test { faultsim_test_result {0 {}} } + +} + #--------------------------------------------------------------------------- # Test fault injection into a small backup operation. # do_test pagerfault-14-pre1 { @@ -630,16 +633,31 @@ INSERT INTO t2 VALUES(a_string(333), a_string(444)); COMMIT; } faultsim_save_and_close } {} -do_faultsim_test pagerfault-14 -prep { + +do_faultsim_test pagerfault-14a -prep { faultsim_restore_and_reopen } -body { if {[catch {db backup test.db2} msg]} { error [regsub {.*: } $msg {}] } } -test { faultsim_test_result {0 {}} {1 {}} {1 {SQL logic error or missing database}} +} +do_faultsim_test pagerfault-14b -prep { + faultsim_restore_and_reopen + sqlite3 db2 "" + db2 eval { PRAGMA page_size = 4096; CREATE TABLE xx(a) } +} -body { + sqlite3_backup B db2 main db main + B step 200 + set rc [B finish] + if {[string match SQLITE_IOERR_* $rc]} {set rc SQLITE_IOERR} + if {$rc != "SQLITE_OK"} { error [sqlite3_test_errstr $rc] } + set {} {} +} -test { + faultsim_test_result {0 {}} } do_test pagerfault-15-pre1 { faultsim_delete_and_reopen db func a_string a_string; @@ -665,11 +683,10 @@ } -test { faultsim_test_result {0 {}} faultsim_integrity_check } -} do_test pagerfault-16-pre1 { faultsim_delete_and_reopen execsql { CREATE TABLE t1(x, y UNIQUE) } faultsim_save_and_close