Index: src/wal.c ================================================================== --- src/wal.c +++ src/wal.c @@ -1224,10 +1224,13 @@ pRet->zWalName = zWalName; /* Open file handle on the write-ahead log file. */ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags); + if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){ + rc = SQLITE_CANTOPEN; + } if( rc!=SQLITE_OK ){ walIndexClose(pRet, 0); sqlite3OsClose(pRet->pWalFd); sqlite3_free(pRet); Index: test/malloc_common.tcl ================================================================== --- test/malloc_common.tcl +++ test/malloc_common.tcl @@ -135,10 +135,11 @@ #------------------------------------------------------------------------- # Procedures to save and restore the current file-system state: # # faultsim_save +# faultsim_restore # faultsim_save_and_close # faultsim_restore_and_reopen # faultsim_delete_and_reopen # proc faultsim_save {} { @@ -151,17 +152,20 @@ proc faultsim_save_and_close {} { faultsim_save catch { db close } return "" } -proc faultsim_restore_and_reopen {{dbfile test.db}} { - catch { db close } +proc faultsim_restore {} { foreach f [glob -nocomplain test.db*] { file delete -force $f } foreach f2 [glob -nocomplain sv_test.db*] { set f [string range $f2 3 end] file copy -force $f2 $f } +} +proc faultsim_restore_and_reopen {{dbfile test.db}} { + catch { db close } + faultsim_restore sqlite3 db $dbfile sqlite3_extended_result_codes db 1 sqlite3_db_config_lookaside db 0 0 0 } Index: test/wal2.test ================================================================== --- test/wal2.test +++ test/wal2.test @@ -1003,12 +1003,12 @@ # the new files with the same file-system permissions as the database # file itself. Test this. # if {$::tcl_platform(platform) == "unix"} { faultsim_delete_and_reopen - set umask [exec /bin/sh -c umask] + do_test wal2-12.1 { sqlite3 db test.db execsql { CREATE TABLE tx(y, z); PRAGMA journal_mode = WAL; @@ -1043,8 +1043,99 @@ db close list [file exists test.db-wal] [file exists test.db-shm] } {0 0} } } + +#------------------------------------------------------------------------- +# Test the libraries response to discovering that one or more of the +# database, wal or shm files cannot be opened, or can only be opened +# read-only. +# +if {$::tcl_platform(platform) == "unix"} { + proc perm {} { + set L [list] + foreach f {test.db test.db-wal test.db-shm} { + if {[file exists $f]} { + lappend L [file attr $f -perm] + } else { + lappend L {} + } + } + set L + } + + faultsim_delete_and_reopen + execsql { + PRAGMA journal_mode = WAL; + CREATE TABLE t1(a, b); + PRAGMA wal_checkpoint; + INSERT INTO t1 VALUES('3.14', '2.72'); + } + do_test wal2-13.1.1 { + list [file exists test.db-shm] [file exists test.db-wal] + } {1 1} + faultsim_save_and_close + + foreach {tn db_perm wal_perm shm_perm can_open can_read can_write} { + 2 00644 00644 00644 1 1 1 + 3 00644 00400 00644 1 0 0 + 4 00644 00644 00400 1 0 0 + 5 00400 00644 00644 1 1 0 + + 7 00644 00000 00644 1 0 0 + 8 00644 00644 00000 1 0 0 + 9 00000 00644 00644 0 0 0 + } { + faultsim_restore + do_test wal2-13.$tn.1 { + file attr test.db -perm $db_perm + file attr test.db-wal -perm $wal_perm + file attr test.db-shm -perm $shm_perm + + set L [file attr test.db -perm] + lappend L [file attr test.db-wal -perm] + lappend L [file attr test.db-shm -perm] + } [list $db_perm $wal_perm $shm_perm] + + # If $can_open is true, then it should be possible to open a database + # handle. Otherwise, if $can_open is 0, attempting to open the db + # handle throws an "unable to open database file" exception. + # + set r(1) {0 ok} + set r(0) {1 {unable to open database file}} + do_test wal2-13.$tn.2 { + list [catch {sqlite3 db test.db ; set {} ok} msg] $msg + } $r($can_open) + + if {$can_open} { + + # If $can_read is true, then the client should be able to read from + # the database file. If $can_read is false, attempting to read should + # throw the "unable to open database file" exception. + # + set a(0) {1 {unable to open database file}} + set a(1) {0 {3.14 2.72}} + do_test wal2-13.$tn.3 { + catchsql { SELECT * FROM t1 } + } $a($can_read) + + # Now try to write to the db file. If the client can read but not + # write, then it should throw the familiar "unable to open db file" + # exception. If it can read but not write, the exception should + # be "attempt to write a read only database". + # + # If the client can read and write, the operation should succeed. + # + set b(0,0) {1 {unable to open database file}} + set b(1,0) {1 {attempt to write a readonly database}} + set b(1,1) {0 {}} + do_test wal2-13.$tn.4 { + catchsql { INSERT INTO t1 DEFAULT VALUES } + } $b($can_read,$can_write) + } + catch { db close } + } +} finish_test