Add experimental support for read-only connections to WAL databases.
FossilOrigin-Name: bb59f9862da45d25fb51d7821130854828c91c98
This commit is contained in:
parent
de941c3756
commit
4edc6bf3ee
26
manifest
26
manifest
@ -1,5 +1,5 @@
|
||||
C Return\sa\ssuitable\serror\smessage\sif\sthe\smode=\sargument\sto\sa\sURI\sspecifies\na\shigher\smode\sthan\swhat\sis\sallowed\sby\scontext.\s\sOther\sminor\scleanups\sfor\nthe\sURI\sparsing\slogic.
|
||||
D 2011-05-09T19:20:17.775
|
||||
C Add\sexperimental\ssupport\sfor\sread-only\sconnections\sto\sWAL\sdatabases.
|
||||
D 2011-05-10T17:31:29.338
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -163,7 +163,7 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
|
||||
F src/os_unix.c 2c67d126874b78eb427371db4793f0e8fbc7448b
|
||||
F src/os_unix.c 03630dd062c3d1fb9f25e2a227048b709c5babff
|
||||
F src/os_win.c ff0e14615a5086fa5ba6926e4ec0dc9cfb5a1a84
|
||||
F src/pager.c 24b689bc3639d534f5fb292d2c68038b1e720527
|
||||
F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
|
||||
@ -179,14 +179,14 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c d9d440809025a58547e39f4f268c2a296bfb56ff
|
||||
F src/shell.c 72e7e176bf46d5c6518d15ac4ad6847c4bb5df79
|
||||
F src/sqlite.h.in 41a0e4bc842917226e170273f64b95717a63270a
|
||||
F src/sqlite.h.in e7bbcb330ced6b5e25c9db8089c2c77aaefadf7d
|
||||
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
|
||||
F src/sqliteInt.h b34bd64a7ade4808fcc301e0bb67ef5051ea49c6
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 501c9a200fd998a268be475be5858febc90b725b
|
||||
F src/test1.c f506164085bc4cbbb4b5c14b9c6de153f1aeafc5
|
||||
F src/test1.c 6ae026cd9d2b1b1e95a372a7460d091705db645d
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
|
||||
F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
|
||||
@ -245,7 +245,7 @@ F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562
|
||||
F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
|
||||
F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
|
||||
F src/vtab.c 48dcef8bc757c2e7b488f68b5ddebb1650da2450
|
||||
F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794
|
||||
F src/wal.c 2574b16ee88b1934e97f63ae38025dc48ef45327
|
||||
F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 55403ce19c506be6a321c7f129aff693d6103db5
|
||||
@ -547,7 +547,7 @@ F test/lock4.test c82268c031d39345d05efa672f80b025481b3ae5
|
||||
F test/lock5.test b2abb5e711bc59b0eae00f6c97a36ec9f458fada
|
||||
F test/lock6.test ad5b387a3a8096afd3c68a55b9535056431b0cf5
|
||||
F test/lock7.test 64006c84c1c616657e237c7ad6532b765611cf64
|
||||
F test/lock_common.tcl d279887a0ab16cdb6d935c1203e64113c5a000e9
|
||||
F test/lock_common.tcl 0c270b121d40959fa2f3add382200c27045b3d95
|
||||
F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2
|
||||
F test/main.test 9d7bbfcc1b52c88ba7b2ba6554068ecf9939f252
|
||||
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
@ -883,6 +883,7 @@ F test/walfault.test 58fce626359c9376fe35101b5c0f2df8040aa839
|
||||
F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483
|
||||
F test/walmode.test 22ddccd073c817ac9ead62b88ac446e8dedc7d2c
|
||||
F test/walnoshm.test a074428046408f4eb5c6a00e09df8cc97ff93317
|
||||
F test/walro.test 0fb4c79a9dfa1d14f46859e469d3b4844480cd9d
|
||||
F test/walshared.test 6dda2293880c300baf5d791c307f653094585761
|
||||
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
||||
F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c
|
||||
@ -935,7 +936,10 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P ca3797d4967361e31a8a5ce1ce8190b095f3ed4c
|
||||
R fbfaa47316ae48b91e92f26cbe2f2742
|
||||
U drh
|
||||
Z 82e3dc394cc5052bfb9a5a6a21e4f298
|
||||
P d9bc1c7fe0ca5f6973a85827330958f4d09f8171
|
||||
R 864e9c4ee7a6cf5f8240415fb38d1af8
|
||||
T *branch * wal-readonly
|
||||
T *sym-wal-readonly *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z 321776a9f8d852e48652ad186c3a479b
|
||||
|
@ -1 +1 @@
|
||||
d9bc1c7fe0ca5f6973a85827330958f4d09f8171
|
||||
bb59f9862da45d25fb51d7821130854828c91c98
|
@ -212,6 +212,7 @@ struct unixFile {
|
||||
UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
|
||||
const char *zPath; /* Name of the file */
|
||||
unixShm *pShm; /* Shared memory segment information */
|
||||
int readOnlyShm; /* True to open shared-memory read-only */
|
||||
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
int openFlags; /* The flags specified at open() */
|
||||
@ -3452,6 +3453,10 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
case SQLITE_FCNTL_SIZE_HINT: {
|
||||
return fcntlSizeHint((unixFile *)id, *(i64 *)pArg);
|
||||
}
|
||||
case SQLITE_FCNTL_READONLY_SHM: {
|
||||
((unixFile*)id)->readOnlyShm = (pArg!=0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
/* The pager calls this method to signal that it has done
|
||||
** a rollback and that the database is therefore unchanged and
|
||||
@ -3541,6 +3546,7 @@ struct unixShmNode {
|
||||
char **apRegion; /* Array of mapped shared-memory regions */
|
||||
int nRef; /* Number of unixShm objects pointing to this */
|
||||
unixShm *pFirst; /* All unixShm objects pointing to this */
|
||||
u8 readOnly; /* True if this is a read-only mapping */
|
||||
#ifdef SQLITE_DEBUG
|
||||
u8 exclMask; /* Mask of exclusive locks held */
|
||||
u8 sharedMask; /* Mask of shared locks held */
|
||||
@ -3780,29 +3786,48 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
||||
}
|
||||
|
||||
if( pInode->bProcessLock==0 ){
|
||||
pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
|
||||
(sStat.st_mode & 0777));
|
||||
int flags = (pDbFd->readOnlyShm ? O_RDONLY : O_RDWR|O_CREAT);
|
||||
pShmNode->h = robust_open(zShmFilename, flags, (sStat.st_mode & 0777));
|
||||
if( pShmNode->h<0 ){
|
||||
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
|
||||
goto shm_open_err;
|
||||
}
|
||||
pShmNode->readOnly = pDbFd->readOnlyShm;
|
||||
|
||||
/* Check to see if another process is holding the dead-man switch.
|
||||
** If not, truncate the file to zero length.
|
||||
*/
|
||||
rc = SQLITE_OK;
|
||||
if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
|
||||
if( robust_ftruncate(pShmNode->h, 0) ){
|
||||
rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
|
||||
** If not, zero the first few bytes of the shared-memory file to make
|
||||
** sure it is not mistaken for valid by code in wal.c. Except, if this
|
||||
** is a read-only connection to the shared-memory then it is not possible
|
||||
** to check check if another process is holding a read-lock on the DMS
|
||||
** byte, as we cannot attempt a write-lock via a read-only file
|
||||
** descriptor. So in this case, we just assume the shared-memory
|
||||
** contents are Ok and proceed. */
|
||||
if( pShmNode->readOnly==0 ){
|
||||
rc = SQLITE_OK;
|
||||
if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
|
||||
if( pDbFd->readOnlyShm ){
|
||||
rc = SQLITE_IOERR_SHMOPEN;
|
||||
}else if( 4!=osWrite(pShmNode->h, "\00\00\00\00", 4) ){
|
||||
rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
|
||||
}
|
||||
if( rc ) goto shm_open_err;
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
|
||||
}
|
||||
if( rc ) goto shm_open_err;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the unixShmNode is read-only, but SQLITE_FCNTL_READONLY_SHM has not
|
||||
** been set for file-descriptor pDbFd, return an error. The wal.c module
|
||||
** will then call this function again with SQLITE_FCNTL_READONLY_SHM set.
|
||||
*/
|
||||
else if( pShmNode->readOnly && !pDbFd->readOnlyShm ){
|
||||
rc = SQLITE_IOERR_SHMOPEN;
|
||||
goto shm_open_err;
|
||||
}
|
||||
|
||||
/* Make the new connection a child of the unixShmNode */
|
||||
p->pShmNode = pShmNode;
|
||||
#ifdef SQLITE_DEBUG
|
||||
@ -3923,7 +3948,7 @@ static int unixShmMap(
|
||||
while(pShmNode->nRegion<=iRegion){
|
||||
void *pMem;
|
||||
if( pShmNode->h>=0 ){
|
||||
pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE,
|
||||
pMem = mmap(0, szRegion, PROT_READ|(!pShmNode->readOnly?PROT_WRITE:0),
|
||||
MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
|
||||
);
|
||||
if( pMem==MAP_FAILED ){
|
||||
|
@ -454,6 +454,9 @@ int sqlite3_exec(
|
||||
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
||||
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
|
||||
|
||||
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
|
||||
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
|
||||
|
||||
/*
|
||||
** CAPI3REF: Flags For File Open Operations
|
||||
**
|
||||
@ -742,6 +745,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_CHUNK_SIZE 6
|
||||
#define SQLITE_FCNTL_FILE_POINTER 7
|
||||
#define SQLITE_FCNTL_SYNC_OMITTED 8
|
||||
#define SQLITE_FCNTL_READONLY_SHM 9
|
||||
|
||||
|
||||
/*
|
||||
|
@ -163,6 +163,9 @@ const char *sqlite3TestErrorName(int rc){
|
||||
case SQLITE_IOERR_CHECKRESERVEDLOCK:
|
||||
zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
|
||||
case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break;
|
||||
|
||||
case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break;
|
||||
case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break;
|
||||
default: zName = "SQLITE_Unknown"; break;
|
||||
}
|
||||
return zName;
|
||||
|
59
src/wal.c
59
src/wal.c
@ -420,6 +420,7 @@ struct Wal {
|
||||
u8 writeLock; /* True if in a write transaction */
|
||||
u8 ckptLock; /* True if holding a checkpoint lock */
|
||||
u8 readOnly; /* True if the WAL file is open read-only */
|
||||
u8 readOnlyShm; /* True if the SHM file is open read-only */
|
||||
WalIndexHdr hdr; /* Wal-index header for current transaction */
|
||||
const char *zWalName; /* Name of WAL file */
|
||||
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
|
||||
@ -528,6 +529,16 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
|
||||
rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
|
||||
pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
|
||||
);
|
||||
if( rc==SQLITE_CANTOPEN && iPage==0 ){
|
||||
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_READONLY_SHM, (void*)1);
|
||||
rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
|
||||
pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
|
||||
);
|
||||
if( rc==SQLITE_OK ){
|
||||
pWal->readOnly = pWal->readOnlyShm = 1;
|
||||
}
|
||||
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_READONLY_SHM, (void*)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -772,6 +783,7 @@ static void walUnlockShared(Wal *pWal, int lockIdx){
|
||||
}
|
||||
static int walLockExclusive(Wal *pWal, int lockIdx, int n){
|
||||
int rc;
|
||||
assert( pWal->readOnlyShm==0 );
|
||||
if( pWal->exclusiveMode ) return SQLITE_OK;
|
||||
rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
|
||||
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
|
||||
@ -781,6 +793,7 @@ static int walLockExclusive(Wal *pWal, int lockIdx, int n){
|
||||
return rc;
|
||||
}
|
||||
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
|
||||
assert( pWal->readOnlyShm==0 );
|
||||
if( pWal->exclusiveMode ) return;
|
||||
(void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
|
||||
SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
|
||||
@ -1056,6 +1069,7 @@ static int walIndexRecover(Wal *pWal){
|
||||
assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
|
||||
assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
|
||||
assert( pWal->writeLock );
|
||||
assert( pWal->readOnlyShm==0 );
|
||||
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
|
||||
nLock = SQLITE_SHM_NLOCK - iLock;
|
||||
rc = walLockExclusive(pWal, iLock, nLock);
|
||||
@ -1904,24 +1918,31 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
||||
badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
|
||||
|
||||
/* If the first attempt failed, it might have been due to a race
|
||||
** with a writer. So get a WRITE lock and try again.
|
||||
** with a writer. So lock the WAL_WRITE_LOCK byte and try again.
|
||||
*/
|
||||
assert( badHdr==0 || pWal->writeLock==0 );
|
||||
if( badHdr && SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
|
||||
pWal->writeLock = 1;
|
||||
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
||||
badHdr = walIndexTryHdr(pWal, pChanged);
|
||||
if( badHdr ){
|
||||
/* If the wal-index header is still malformed even while holding
|
||||
** a WRITE lock, it can only mean that the header is corrupted and
|
||||
** needs to be reconstructed. So run recovery to do exactly that.
|
||||
*/
|
||||
rc = walIndexRecover(pWal);
|
||||
*pChanged = 1;
|
||||
if( badHdr ){
|
||||
if( pWal->readOnlyShm ){
|
||||
if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
|
||||
walUnlockShared(pWal, WAL_WRITE_LOCK);
|
||||
rc = SQLITE_READONLY_RECOVERY;
|
||||
}
|
||||
}else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
|
||||
pWal->writeLock = 1;
|
||||
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
||||
badHdr = walIndexTryHdr(pWal, pChanged);
|
||||
if( badHdr ){
|
||||
/* If the wal-index header is still malformed even while holding
|
||||
** a WRITE lock, it can only mean that the header is corrupted and
|
||||
** needs to be reconstructed. So run recovery to do exactly that.
|
||||
*/
|
||||
rc = walIndexRecover(pWal);
|
||||
*pChanged = 1;
|
||||
}
|
||||
}
|
||||
pWal->writeLock = 0;
|
||||
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||
}
|
||||
pWal->writeLock = 0;
|
||||
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||
}
|
||||
|
||||
/* If the header is read successfully, check the version number to make
|
||||
@ -2108,7 +2129,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
}
|
||||
/* There was once an "if" here. The extra "{" is to preserve indentation. */
|
||||
{
|
||||
if( mxReadMark < pWal->hdr.mxFrame || mxI==0 ){
|
||||
if( pWal->readOnlyShm==0 && (mxReadMark < pWal->hdr.mxFrame || mxI==0) ){
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
@ -2123,7 +2144,8 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
}
|
||||
if( mxI==0 ){
|
||||
assert( rc==SQLITE_BUSY );
|
||||
return WAL_RETRY;
|
||||
assert( rc==SQLITE_BUSY || (pWal->readOnlyShm && rc==SQLITE_OK) );
|
||||
return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
|
||||
}
|
||||
|
||||
rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
|
||||
@ -2359,6 +2381,7 @@ int sqlite3WalBeginWriteTransaction(Wal *pWal){
|
||||
if( pWal->readOnly ){
|
||||
return SQLITE_READONLY;
|
||||
}
|
||||
assert( pWal->readOnlyShm==0 );
|
||||
|
||||
/* Only one writer allowed at a time. Get the write lock. Return
|
||||
** SQLITE_BUSY if unable.
|
||||
@ -2748,6 +2771,10 @@ int sqlite3WalCheckpoint(
|
||||
assert( pWal->writeLock==0 );
|
||||
|
||||
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
|
||||
if( pWal->readOnlyShm ){
|
||||
return SQLITE_READONLY;
|
||||
}
|
||||
|
||||
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
||||
if( rc ){
|
||||
/* Usually this is SQLITE_BUSY meaning that another thread or process
|
||||
|
@ -55,8 +55,8 @@ proc do_multiclient_test {varname script} {
|
||||
uplevel set $varname $tn
|
||||
uplevel $script
|
||||
|
||||
code2 { db2 close }
|
||||
code3 { db3 close }
|
||||
catch { code2 { db2 close } }
|
||||
catch { code3 { db3 close } }
|
||||
catch { close $::code2_chan }
|
||||
catch { close $::code3_chan }
|
||||
catch { db close }
|
||||
|
121
test/walro.test
Normal file
121
test/walro.test
Normal file
@ -0,0 +1,121 @@
|
||||
# 2011 May 09
|
||||
#
|
||||
# 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 contains tests for using WAL databases in read-only mode.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
set ::testprefix walro
|
||||
|
||||
|
||||
do_multiclient_test tn {
|
||||
# These tests are only going to work on unix.
|
||||
#
|
||||
if {$tcl_platform(platform) != "unix"} continue
|
||||
|
||||
# Do not run tests with the connections in the same process.
|
||||
#
|
||||
if {$tn==2} continue
|
||||
|
||||
# Close all connections and delete the database.
|
||||
#
|
||||
code1 { db close }
|
||||
code2 { db2 close }
|
||||
code3 { db3 close }
|
||||
forcedelete test.db
|
||||
forcedelete walro
|
||||
|
||||
file mkdir walro
|
||||
|
||||
do_test 1.1.1 {
|
||||
code2 { sqlite3 db2 test.db }
|
||||
sql2 {
|
||||
PRAGMA journal_mode = WAL;
|
||||
CREATE TABLE t1(x, y);
|
||||
INSERT INTO t1 VALUES('a', 'b');
|
||||
}
|
||||
file exists test.db-shm
|
||||
} {1}
|
||||
|
||||
do_test 1.1.2 {
|
||||
file attributes test.db-shm -permissions r--r--r--
|
||||
code1 { sqlite3 db test.db }
|
||||
} {}
|
||||
|
||||
do_test 1.1.3 { sql1 "SELECT * FROM t1" } {a b}
|
||||
do_test 1.1.4 { sql2 "INSERT INTO t1 VALUES('c', 'd')" } {}
|
||||
do_test 1.1.5 { sql1 "SELECT * FROM t1" } {a b c d}
|
||||
|
||||
# Check that the read-only connection cannot write or checkpoint the db.
|
||||
#
|
||||
do_test 1.1.6 {
|
||||
csql1 "INSERT INTO t1 VALUES('e', 'f')"
|
||||
} {1 {attempt to write a readonly database}}
|
||||
do_test 1.1.7 {
|
||||
csql1 "PRAGMA wal_checkpoint"
|
||||
} {1 {attempt to write a readonly database}}
|
||||
|
||||
do_test 1.1.9 { sql2 "INSERT INTO t1 VALUES('e', 'f')" } {}
|
||||
do_test 1.1.10 { sql1 "SELECT * FROM t1" } {a b c d e f}
|
||||
|
||||
do_test 1.1.11 {
|
||||
sql2 {
|
||||
INSERT INTO t1 VALUES('g', 'h');
|
||||
PRAGMA wal_checkpoint;
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
do_test 1.1.12 { sql1 "SELECT * FROM t1" } {a b c d e f g h}
|
||||
do_test 1.1.13 { sql2 "INSERT INTO t1 VALUES('i', 'j')" } {}
|
||||
|
||||
do_test 1.2.1 {
|
||||
code2 { db2 close }
|
||||
code1 { db close }
|
||||
list [file exists test.db-wal] [file exists test.db-shm]
|
||||
} {1 1}
|
||||
do_test 1.2.2 {
|
||||
code1 { sqlite3 db test.db }
|
||||
sql1 { SELECT * FROM t1 }
|
||||
} {a b c d e f g h i j}
|
||||
|
||||
do_test 1.2.3 {
|
||||
code1 { db close }
|
||||
file attributes test.db-shm -permissions rw-r--r--
|
||||
hexio_write test.db-shm 0 01020304
|
||||
file attributes test.db-shm -permissions r--r--r--
|
||||
code1 { sqlite3 db test.db }
|
||||
csql1 { SELECT * FROM t1 }
|
||||
} {1 {attempt to write a readonly database}}
|
||||
do_test 1.2.4 {
|
||||
code1 { sqlite3_extended_errcode db }
|
||||
} {SQLITE_READONLY_RECOVERY}
|
||||
|
||||
do_test 1.2.5 {
|
||||
file attributes test.db-shm -permissions rw-r--r--
|
||||
code2 { sqlite3 db2 test.db }
|
||||
sql2 "SELECT * FROM t1"
|
||||
} {a b c d e f g h i j}
|
||||
file attributes test.db-shm -permissions r--r--r--
|
||||
do_test 1.2.6 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j}
|
||||
|
||||
do_test 1.2.7 {
|
||||
sql2 {
|
||||
PRAGMA wal_checkpoint;
|
||||
INSERT INTO t1 VALUES('k', 'l');
|
||||
}
|
||||
set {} {}
|
||||
} {}
|
||||
do_test 1.2.8 { sql1 "SELECT * FROM t1" } {a b c d e f g h i j k l}
|
||||
}
|
||||
|
||||
finish_test
|
Loading…
x
Reference in New Issue
Block a user