Forward port the Apple-specific changes from [db5b7b778c] in the

apple-osx-377 branch.  Fix this up so that it will compile and run on Linux.

FossilOrigin-Name: 6cb43f6c6e9d8054e00acab378b8af0d82d3084c
This commit is contained in:
drh
2011-10-10 23:53:48 +00:00
14 changed files with 614 additions and 442 deletions
+17 -17
View File
@@ -1,5 +1,5 @@
C Merge\sin\sall\strunk\schanges\sthrough\sthe\s3.7.8\srelease.
D 2011-09-19T20:32:36.507
C Forward\sport\sthe\sApple-specific\schanges\sfrom\s[db5b7b778c]\sin\sthe\napple-osx-377\sbranch.\s\sFix\sthis\sup\sso\sthat\sit\swill\scompile\sand\srun\son\sLinux.
D 2011-10-10T23:53:48.384
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 55bbee3ada084d4aa4dab9e1e0d90a21aab8bbcf
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -124,7 +124,7 @@ F src/alter.c ac80a0f31189f8b4a524ebf661e47e84536ee7f5
F src/analyze.c a425d62e8fa9ebcb4359ab84ff0c62c6563d2e2a
F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 28a4fe55327ff708bfaf9d4326d02686f7a553c3
F src/backup.c 5774963f44ed38c56561033694d3a5ad516c556b
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 71a65f9bbdc3c93bd0f043aa9148b751474cea5e
@@ -149,10 +149,10 @@ F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
F src/legacy.c 015826a958f690302d27e096a68d50b3657e4201
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
F src/loadext.c 99a161b27a499fc8ad40745b7b1900a26f0a5f51
F src/main.c 242eaa584e256364f81f2aef97d3eca283d94073
F src/main.c 4aabaa8d510c08d59595be5d83c4d630e8200982
F src/malloc.c 591aedb20ae40813f1045f2ef253438a334775d9
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 46095d62b241466ef51970e592aa3a7a87e443e1
F src/mem1.c c390a8fce10912a770ebe6fa031f5f463649e7ae
F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c c2c63b7067570b00bf33d751c39af24182316f7f
@@ -168,9 +168,9 @@ F src/os.c 0668c16ae226cd58cef8240e5edbd0c93248739e
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
F src/os_unix.c 6fdce4067dc5796b358bd9cf55cf5dd62d580945
F src/os_win.c 0fc0f46c94b0385a940b0ee32992a833019a5985
F src/pager.c 984dc40d797d8d822d6ce1d184287600d94a289f
F src/os_unix.c ed727d5822235e16519e82ba8bb355426381e1be
F src/os_win.c 3fc8f4bb69dd71b2dc6b48e8d5fb411748197470
F src/pager.c 5cafaf3833fceefd21bfa4dd2254b71461663286
F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
F src/pcache.c 49e718c095810c6b3334e3a6d89970aceaddefce
@@ -184,15 +184,15 @@ F src/resolve.c 36368f44569208fa074e61f4dd0b6c4fb60ca2b4
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c f3971442d59d06801ac3c712f2851ece8d1cdead
F src/shell.c 13fe2aeddc3cc90d6a273831d1f63736d1596f81
F src/sqlite.h.in 175065018323ca082092f92873e074647d00bec2
F src/sqlite3_private.h 1d18557420cb0cc51ff31ec0a3fcce11e5cd6f5a
F src/sqlite.h.in 9b74f2d71c15cc9e3f78c16474e2096a707ceba5
F src/sqlite3_private.h e3b586e0aa329075d99be7198df9bc80c5b19e2d
F src/sqlite3ext.h 1a1a4f784aa9c3b00edd287940197de52487cd93
F src/sqliteInt.h 751564e4eb28a49d4f53f7bd2a211a48115d01d7
F src/sqliteInt.h e9a32825290cee916e3e0939c857a13801afc700
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 3ef1dda2f1dc207c792eaadebf9d8adc44648581
F src/test1.c 48759e7898dd7af7ae2b01de12045814583e15c6
F src/test1.c 63a00ab722cc49025a6f675bcda39bed83663a48
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
@@ -246,13 +246,13 @@ F src/vdbe.c 26deb38f5bd32ebeb2cb60853a52f2bf33d71641
F src/vdbe.h f0725ee997db869ecae5bb70a71612aabeca7755
F src/vdbeInt.h 693d6ac6810298fc6b4c503cfbe3f99a240f40af
F src/vdbeapi.c 335435e65443f38d3073b5043e80cbbb7090c2d9
F src/vdbeaux.c 49be7a5ce6a1b7df9ef5791133c3e4e6ab2a1ffe
F src/vdbeaux.c 669fe607968e058ef49f7ed7846efde4fece5848
F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
F src/vdbemem.c 5e6effb96dd53d233361cbfaa3f0a43b9af689e9
F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
F src/vdbetrace.c 4b92fe7355f682368203d29b2be7125cbab85e79
F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582
F src/wal.c 92c7c876b026d5e38fab3ce332e49266ffcf8b2b
F src/wal.c eea77c324942f7e31ce9c3a5e6e86c4a0424fa09
F src/wal.h e75d87752bd5df3dc4152ee2cb3b0dcd0b309e5e
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c b641d399cfd8588d0e20d9790d1582b663a732a8
@@ -968,7 +968,7 @@ F tool/symbols.sh caaf6ccc7300fd43353318b44524853e222557d5
F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings.sh b7fdb2cc525f5ef4fa43c80e771636dd3690f9d2
P ffed86bf969b98d196ac50bb5e5faddecab4fc59 3e0da808d2f5b4d12046e05980ca04578f581177
R fab0c6c716ebe505f8c308159e4b4eab
P ade72b1874c7672ae8d62b9ebac8e4d63fee80cc db5b7b778c09c57501cb8266895a0ea4f2de7649
R 492a1b6738940e27b5c3378a18dde5be
U drh
Z 7d1fe25483dc7359b7f468acf5aa09ab
Z 7f2d52c0164fc6fa32a2a1d8b7959b0c
+1 -1
View File
@@ -1 +1 @@
ade72b1874c7672ae8d62b9ebac8e4d63fee80cc
6cb43f6c6e9d8054e00acab378b8af0d82d3084c
+9
View File
@@ -419,6 +419,15 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
if( destMode==PAGER_JOURNALMODE_WAL ){
rc = sqlite3BtreeSetVersion(p->pDest, 2);
}
}
if( destMode==PAGER_JOURNALMODE_WAL ){
/* This call cannot fail. The success of the BtreeUpdateMeta()
** method above indicates that a write transaction has been opened
** and page 1 is already dirty. Therefore this always succeeds.
*/
TESTONLY(int rc2 =) sqlite3BtreeSetVersion(p->pDest, 2);
assert( rc2==SQLITE_OK );
}
if( rc==SQLITE_OK ){
int nDestTruncate;
+10 -128
View File
@@ -2989,144 +2989,26 @@ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
return 0;
}
#if (SQLITE_ENABLE_APPLE_SPI>0)
#define SQLITE_FILE_HEADER_LEN 16
#include <fcntl.h>
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
#include "sqlite3_private.h"
#include "btreeInt.h"
#include <errno.h>
#include <sys/param.h>
/* Check for a conflicting lock. If one is found, print an this
** on standard output using the format string given and return 1.
** If there are no conflicting locks, return 0.
*/
static int isLocked(
pid_t pid, /* PID to test for lock owner */
int h, /* File descriptor to check */
int type, /* F_RDLCK or F_WRLCK */
unsigned int iOfst, /* First byte of the lock */
unsigned int iCnt, /* Number of bytes in the lock range */
const char *zType /* Type of lock */
){
struct flock lk;
int err;
memset(&lk, 0, sizeof(lk));
lk.l_type = type;
lk.l_whence = SEEK_SET;
lk.l_start = iOfst;
lk.l_len = iCnt;
if( pid!=SQLITE_LOCKSTATE_ANYPID ){
#ifndef F_GETLKPID
# warning F_GETLKPID undefined, _sqlite3_lockstate falling back to F_GETLK
err = fcntl(h, F_GETLK, &lk);
#else
lk.l_pid = pid;
err = fcntl(h, F_GETLKPID, &lk);
#endif
}else{
err = fcntl(h, F_GETLK, &lk);
}
if( err==(-1) ){
fprintf(stderr, "fcntl(%d) failed: errno=%d\n", h, errno);
return -1;
}
if( lk.l_type!=F_UNLCK && (pid==SQLITE_LOCKSTATE_ANYPID || lk.l_pid==pid) ){
#ifdef SQLITE_DEBUG
fprintf(stderr, "%s lock held by %d\n", zType, (int)lk.l_pid);
#endif
return 1;
}
return 0;
}
/*
** Location of locking bytes in the database file
*/
#ifndef PENDING_BYTE
# define PENDING_BYTE (0x40000000)
# define RESERVED_BYTE (PENDING_BYTE+1)
# define SHARED_FIRST (PENDING_BYTE+2)
# define SHARED_SIZE 510
#endif /* PENDING_BYTE */
/*
** Lock locations for shared-memory locks used by WAL mode.
*/
#ifndef SHM_BASE
# define SHM_BASE 120
# define SHM_WRITE SHM_BASE
# define SHM_CHECKPOINT (SHM_BASE+1)
# define SHM_RECOVER (SHM_BASE+2)
# define SHM_READ_FIRST (SHM_BASE+3)
# define SHM_READ_SIZE 5
#endif /* SHM_BASE */
/*
** Testing a file path for sqlite locks held by a process ID.
** Returns SQLITE_LOCKSTATE_ON if locks are present on path
** that would prevent writing to the database.
**
** This test only works for lock testing on unix/posix VFS.
** Adapted from tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
*/
int _sqlite3_lockstate(const char *path, pid_t pid){
int hDb; /* File descriptor for the open database file */
int hShm; /* File descriptor for WAL shared-memory file */
ssize_t got; /* Bytes read from header */
int isWal; /* True if in WAL mode */
int nLock = 0; /* Number of locks held */
unsigned char aHdr[100]; /* Database header */
sqlite3 *db = NULL;
/* Open the file at path and make sure we are dealing with a database file */
hDb = open(path, O_RDONLY | O_NOCTTY);
if( hDb<0 ){
return SQLITE_LOCKSTATE_ERROR;
if( sqlite3_open_v2(path, &db, SQLITE_OPEN_READONLY, NULL) == SQLITE_OK ){
LockstatePID lockstate = {pid, -1};
sqlite3_file_control(db, NULL, SQLITE_FCNTL_LOCKSTATE_PID, &lockstate);
sqlite3_close(db);
int state = lockstate.state;
return state;
}
assert( (strlen(SQLITE_FILE_HEADER)+1)==SQLITE_FILE_HEADER_LEN );
got = pread(hDb, aHdr, 100, 0);
if( got<0 ){
close(hDb);
return SQLITE_LOCKSTATE_ERROR;
}
if( got!=100 || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0 ){
close(hDb);
return SQLITE_LOCKSTATE_NOTADB;
}
/* First check for an exclusive lock */
nLock += isLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE");
isWal = aHdr[18]==2;
if( nLock==0 && isWal==0 ){
/* Rollback mode */
nLock += isLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2, "PENDING|RESERVED|SHARED");
}
close(hDb);
if( nLock==0 && isWal!=0 ){
char zShm[MAXPATHLEN];
close(hDb);
/* WAL mode */
strlcpy(zShm, path, MAXPATHLEN);
strlcat(zShm, "-shm", MAXPATHLEN);
hShm = open(zShm, O_RDONLY, 0);
if( hShm<0 ){
return SQLITE_LOCKSTATE_OFF;
}
if( isLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ||
isLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){
nLock = 1;
}
close(hShm);
}
if( nLock>0 ){
return SQLITE_LOCKSTATE_ON;
}
return SQLITE_LOCKSTATE_OFF;
return SQLITE_LOCKSTATE_ERROR;
}
#endif /* SQLITE_ENABLE_APPLE_SPI */
+26 -2
View File
@@ -32,7 +32,6 @@
#define SQLITE_FREE(x) free(x)
#define SQLITE_REALLOC(x,y) realloc((x),(y))
#else
@@ -45,6 +44,7 @@ static malloc_zone_t* _sqliteZone_;
#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))
#define SQLITE_MALLOCSIZE(x) (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x))
#endif
@@ -60,7 +60,8 @@ static void *sqlite3MemMalloc(int nByte){
sqlite3_int64 *p;
assert( nByte>0 );
nByte = ROUND8(nByte);
p = SQLITE_MALLOC( nByte+8 );
#ifndef SQLITE_MALLOCSIZE
p = SQLITE_MALLOC( nByte + 8 );
if( p ){
p[0] = nByte;
p++;
@@ -68,6 +69,13 @@ static void *sqlite3MemMalloc(int nByte){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
}
#else
p = SQLITE_MALLOC( nByte );
if( !p ){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
}
#endif
return (void *)p;
}
@@ -82,7 +90,9 @@ static void *sqlite3MemMalloc(int nByte){
static void sqlite3MemFree(void *pPrior){
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 );
#ifndef SQLITE_MALLOCSIZE
p--;
#endif
SQLITE_FREE(p);
}
@@ -91,11 +101,15 @@ static void sqlite3MemFree(void *pPrior){
** or xRealloc().
*/
static int sqlite3MemSize(void *pPrior){
#ifndef SQLITE_MALLOCSIZE
sqlite3_int64 *p;
if( pPrior==0 ) return 0;
p = (sqlite3_int64*)pPrior;
p--;
return (int)p[0];
#else
return (int)SQLITE_MALLOCSIZE(pPrior);
#endif
}
/*
@@ -112,17 +126,27 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
sqlite3_int64 *p = (sqlite3_int64*)pPrior;
assert( pPrior!=0 && nByte>0 );
assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
#ifndef SQLITE_MALLOCSIZE
p--;
p = SQLITE_REALLOC(p, nByte+8 );
if( p ){
p[0] = nByte;
p++;
}else{
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM,
"failed memory resize %u to %u bytes",
sqlite3MemSize(pPrior), nByte);
}
#else
p = SQLITE_REALLOC(p, nByte );
if( !p ){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM,
"failed memory resize %u to %u bytes",
sqlite3MemSize(pPrior), nByte);
}
#endif
return (void*)p;
}
+460 -271
View File
@@ -1574,7 +1574,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
** Zero is returned if the call completes successfully, or -1 if a call
** to fcntl() fails. In this case, errno is set appropriately (by fcntl()).
*/
static int unixFileLock(unixFile *pFile, struct flock *pLock){
static int unixFileLock(unixFile *pFile, struct flock *pLock, int nRetry){
int rc;
unixInodeInfo *pInode = pFile->pInode;
assert( unixMutexHeld() );
@@ -1594,6 +1594,13 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
pInode->bProcessLock = 1;
pInode->nLock++;
}else{
int i = 0;
do {
rc = osFcntl(pFile->h, F_SETLK, pLock);
if( rc && nRetry ){
usleep(100 * (++i));
}
}while( !rc && nRetry-- );
rc = 0;
}
}else{
@@ -1737,7 +1744,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
){
lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
lock.l_start = PENDING_BYTE;
if( unixFileLock(pFile, &lock) ){
if( unixFileLock(pFile, &lock, 0) ){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(rc) ){
@@ -1759,7 +1766,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
/* Now get the read-lock */
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
if( unixFileLock(pFile, &lock) ){
if( unixFileLock(pFile, &lock, 0) ){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
}
@@ -1768,7 +1775,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
lock.l_start = PENDING_BYTE;
lock.l_len = 1L;
lock.l_type = F_UNLCK;
if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
if( unixFileLock(pFile, &lock, 10) && rc==SQLITE_OK ){
/* This could happen with a network mount */
tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
@@ -1809,7 +1816,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
lock.l_len = SHARED_SIZE;
}
if( unixFileLock(pFile, &lock) ){
if( unixFileLock(pFile, &lock, 0) ){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( rc!=SQLITE_BUSY ){
@@ -1930,6 +1937,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
** 4: [RRRR.]
*/
if( eFileLock==SHARED_LOCK ){
int tErrno; /* Error code from system call errors */
#if !defined(__APPLE__) || !SQLITE_ENABLE_LOCKING_STYLE
(void)handleNFSUnlock;
@@ -1937,14 +1945,13 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
#endif
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
if( handleNFSUnlock ){
int tErrno; /* Error code from system call errors */
off_t divSize = SHARED_SIZE - 1;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = divSize;
if( unixFileLock(pFile, &lock)==(-1) ){
if( unixFileLock(pFile, &lock, 10)==(-1) ){
tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
@@ -1960,7 +1967,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = divSize;
if( unixFileLock(pFile, &lock)==(-1) ){
if( unixFileLock(pFile, &lock, 10)==(-1) ){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
if( IS_LOCK_ERROR(rc) ){
@@ -1972,7 +1979,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST+divSize;
lock.l_len = SHARED_SIZE-divSize;
if( unixFileLock(pFile, &lock)==(-1) ){
if( unixFileLock(pFile, &lock, 10)==(-1) ){
tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
@@ -1991,13 +1998,10 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
if( unixFileLock(pFile, &lock) ){
#if OSLOCKING_CHECK_BUSY_IOERR
if( unixFileLock(pFile, &lock, 10) ){
tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
#else
/* In theory, the call to unixFileLock() cannot fail because another
** process is holding an incompatible lock. If it does, this
@@ -2006,8 +2010,11 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
** SQLITE_BUSY would confuse the upper layer (in practice it causes
** an assert to fail). */
rc = SQLITE_IOERR_RDLOCK;
pFile->lastErrno = errno;
pFile->lastErrno = tErrno;
#endif
if( IS_LOCK_ERROR(rc) ){
pFile->lastErrno = tErrno;
}
goto end_unlock;
}
}
@@ -2016,7 +2023,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
lock.l_whence = SEEK_SET;
lock.l_start = PENDING_BYTE;
lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE );
if( unixFileLock(pFile, &lock)==0 ){
if( unixFileLock(pFile, &lock, 10)==0 ){
pInode->eFileLock = SHARED_LOCK;
}else{
#if OSLOCKING_CHECK_BUSY_IOERR
@@ -2045,7 +2052,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
SimulateIOErrorBenign(1);
SimulateIOError( h=(-1) )
SimulateIOErrorBenign(0);
if( unixFileLock(pFile, &lock)==0 ){
if( unixFileLock(pFile, &lock, 10)==0 ){
pInode->eFileLock = NO_LOCK;
}else{
#if OSLOCKING_CHECK_BUSY_IOERR
@@ -3887,6 +3894,419 @@ static int getDbPathForUnixFile(unixFile *pFile, char *dbPath);
#endif
static int isProxyLockingMode(unixFile *);
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
static int unixTruncateDatabase(unixFile *pFile, int bFlags) {
sqlite3_file *id = (sqlite3_file *)pFile;
int rc = SQLITE_OK;
void *pLock = NULL;
int flags = 0;
int corruptFileLock = 0;
int isCorrupt = 0;
#if SQLITE_ENABLE_DATA_PROTECTION
flags |= pFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
if( isProxyLockingMode(pFile) ){
flags |= SQLITE_OPEN_AUTOPROXY;
}
#endif
rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
if( rc ){
if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
isCorrupt = 1;
rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptFileLock);
}
if( rc ){
return rc;
}
}
rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
if( rc==SQLITE_OK ){
unixInvalidateSupportFiles(pFile, 0);
}
pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
if( isCorrupt ){
sqlite3demo_superunlock_corrupt(id, corruptFileLock);
}else{
sqlite3demo_superunlock(pLock);
}
return rc;
}
static int unixInvalidateSupportFiles(unixFile *pFile, int skipWAL) {
char jPath[MAXPATHLEN+9];
int zLen = strlcpy(jPath, pFile->zPath, MAXPATHLEN+9);
if( zLen<MAXPATHLEN ){
size_t jLen;
const char extensions[3][9] = { "-wal", "-journal", "-shm" };
int j = (skipWAL ? 1 : 0);
for( ; j<3; j++ ){
/* Check to see if the shm file is already opened for this pFile */
if( j==2 ){
unixEnterMutex(); /* Because pFile->pInode is shared across threads */
unixShmNode *pShmNode = pFile->pInode->pShmNode;
if( pShmNode && !pShmNode->isReadonly ){
struct stat sStat;
sqlite3_mutex_enter(pShmNode->mutex);
if( pShmNode->h>=0 && !osFstat(pShmNode->h, &sStat) ){
unsigned long size = (sStat.st_size<4) ? sStat.st_size : 4;
if( size>0 ){
bzero(pShmNode->apRegion[0], size);
sqlite3_mutex_leave(pShmNode->mutex);
unixLeaveMutex();
continue;
}
}
sqlite3_mutex_leave(pShmNode->mutex);
}
unixLeaveMutex();
}
jLen = strlcpy(&jPath[zLen], extensions[j], 9);
if( jLen < 9 ){
int jflags = (j<2) ? O_TRUNC : O_RDWR;
int jfd = open(jPath, jflags);
if( jfd==(-1) ){
if( errno!=ENOENT ){
perror(jPath);
}
} else {
if( j==2 ){
struct stat sStat;
if( !osFstat(jfd, &sStat) ){
unsigned long size = (sStat.st_size<4) ? sStat.st_size : 4;
if( size>0 ){
uint32_t zero = 0;
pwrite(jfd, &zero, (size_t)size, 0);
}
}
}
fsync(jfd);
close(jfd);
}
}
}
}
return SQLITE_OK;
}
static int unixReplaceDatabase(unixFile *pFile, sqlite3 *srcdb) {
sqlite3_file *id = (sqlite3_file *)pFile;
Btree *pSrcBtree = NULL;
sqlite3_file *src_file = NULL;
unixFile *pSrcFile = NULL;
char srcWalPath[MAXPATHLEN+5];
int srcWalFD = -1;
int rc = SQLITE_OK;
void *pLock = NULL;
int flags = 0;
sqlite3 *srcdb2 = NULL;
copyfile_state_t s;
int corruptSrcFileLock = 0;
int corruptDstFileLock = 0;
int isSrcCorrupt = 0;
int isDstCorrupt = 0;
if( !sqlite3SafetyCheckOk(srcdb) ){
return SQLITE_MISUSE;
}
#if SQLITE_ENABLE_DATA_PROTECTION
flags |= pFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
if( isProxyLockingMode(pFile) ){
flags |= SQLITE_OPEN_AUTOPROXY;
}
#endif
rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
if( rc ){
if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
isDstCorrupt = 1;
rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptDstFileLock);
}
if( rc ){
return rc;
}
}
/* get the src file descriptor adhering to the db struct access rules
** this code is modeled after sqlite3_file_control() in main.c
*/
sqlite3_mutex_enter(srcdb->mutex);
if( srcdb->nDb>0 ){
pSrcBtree = srcdb->aDb[0].pBt;
}
if( pSrcBtree ){
Pager *pSrcPager;
sqlite3BtreeEnter(pSrcBtree);
pSrcPager = sqlite3BtreePager(pSrcBtree);
assert( pSrcPager!=0 );
src_file = sqlite3PagerFile(pSrcPager);
assert( src_file!=0 );
if( src_file->pMethods ){
int srcFlags = 0;
pSrcFile = (unixFile *)src_file;
/* wal mode db cannot be opened readonly */
if ((pSrcFile->openFlags & O_RDWR) == O_RDWR) {
srcFlags = SQLITE_OPEN_READWRITE;
} else {
srcFlags = SQLITE_OPEN_READONLY;
}
#if SQLITE_ENABLE_DATA_PROTECTION
srcFlags |= pSrcFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
if( isProxyLockingMode(pSrcFile) ){
srcFlags |= SQLITE_OPEN_AUTOPROXY;
}
#endif
rc = sqlite3_open_v2(pSrcFile->zPath, &srcdb2, srcFlags, 0);
if( rc==SQLITE_OK ){
/* start a deferred transaction and read to establish a read lock */
rc = sqlite3_exec(srcdb2, "BEGIN DEFERRED; PRAGMA schema_version", 0, 0, 0);
if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
isSrcCorrupt = 1;
rc = sqlite3demo_superlock_corrupt(src_file, SQLITE_LOCK_SHARED, &corruptSrcFileLock);
}
}
}
}
if( !srcdb2 || pSrcFile==NULL || pSrcFile->h<0){
rc = SQLITE_INTERNAL;
}
if( rc!=SQLITE_OK ){
goto end_replace_database;
}
/* both databases are locked appropriately, copy the src wal journal if
** one exists and then the actual database file
*/
strlcpy(srcWalPath, pSrcFile->zPath, MAXPATHLEN+5);
strlcat(srcWalPath, "-wal", MAXPATHLEN+5);
srcWalFD = open(srcWalPath, O_RDONLY);
if( !(srcWalFD<0) ){
char dstWalPath[MAXPATHLEN+5];
int dstWalFD = -1;
strlcpy(dstWalPath, pFile->zPath, MAXPATHLEN+5);
strlcat(dstWalPath, "-wal", MAXPATHLEN+5);
dstWalFD = open(dstWalPath, O_RDWR|O_CREAT, SQLITE_DEFAULT_FILE_PERMISSIONS);
if( !(dstWalFD<0) ){
s = copyfile_state_alloc();
lseek(srcWalFD, 0, SEEK_SET);
lseek(dstWalFD, 0, SEEK_SET);
if( fcopyfile(srcWalFD, dstWalFD, s, COPYFILE_ALL) ){
int err=errno;
switch(err) {
case ENOMEM:
rc = SQLITE_NOMEM;
break;
default:
pFile->lastErrno = err;
rc = SQLITE_IOERR;
}
}
copyfile_state_free(s);
close(dstWalFD);
}
close(srcWalFD);
}
if( rc==SQLITE_OK ){
/* before we copy, ensure that the file change counter will be modified */
uint32_t srcChange = 0;
uint32_t dstChange = 0;
pread(pSrcFile->h, &srcChange, 4, 24);
pread(pFile->h, &dstChange, 4, 24);
/* copy the actual database */
s = copyfile_state_alloc();
lseek(pSrcFile->h, 0, SEEK_SET);
lseek(pFile->h, 0, SEEK_SET);
if( fcopyfile(pSrcFile->h, pFile->h, s, COPYFILE_ALL) ){
int err=errno;
switch(err) {
case ENOMEM:
rc = SQLITE_NOMEM;
break;
default:
pFile->lastErrno = err;
rc = SQLITE_IOERR;
}
}
copyfile_state_free(s);
if (srcChange == dstChange) {
/* modify the change counter to force page zero to be reloaded */
dstChange ++;
pwrite(pFile->h, &dstChange, 4, 24);
}
}
if( isSrcCorrupt ){
sqlite3demo_superunlock_corrupt(src_file, corruptSrcFileLock);
}else{
/* done with the source db so end the transaction */
sqlite3_exec(srcdb2, "COMMIT", 0, 0, 0);
}
/* zero out any old journal clutter */
if( rc==SQLITE_OK ){
int skipWAL = (srcWalFD<0)?0:1;
unixInvalidateSupportFiles(pFile, skipWAL);
}
end_replace_database:
if( pSrcBtree ){
sqlite3_close(srcdb2);
sqlite3BtreeLeave(pSrcBtree);
}
sqlite3_mutex_leave(srcdb->mutex);
if( isDstCorrupt ){
sqlite3demo_superunlock_corrupt(id, corruptDstFileLock);
}else{
sqlite3demo_superunlock(pLock);
}
return rc;
}
#define SQLITE_FILE_HEADER_LEN 16
#include "btreeInt.h"
/* Check for a conflicting lock. If one is found, print an this
** on standard output using the format string given and return 1.
** If there are no conflicting locks, return 0.
*/
static int unixIsLocked(
pid_t pid, /* PID to test for lock owner */
int h, /* File descriptor to check */
int type, /* F_RDLCK or F_WRLCK */
unsigned int iOfst, /* First byte of the lock */
unsigned int iCnt, /* Number of bytes in the lock range */
const char *zType /* Type of lock */
){
struct flock lk;
int err;
memset(&lk, 0, sizeof(lk));
lk.l_type = type;
lk.l_whence = SEEK_SET;
lk.l_start = iOfst;
lk.l_len = iCnt;
if( pid!=SQLITE_LOCKSTATE_ANYPID ){
#ifndef F_GETLKPID
# warning F_GETLKPID undefined, _sqlite3_lockstate falling back to F_GETLK
err = fcntl(h, F_GETLK, &lk);
#else
lk.l_pid = pid;
err = fcntl(h, F_GETLKPID, &lk);
#endif
}else{
err = fcntl(h, F_GETLK, &lk);
}
if( err==(-1) ){
fprintf(stderr, "fcntl(%d) failed: errno=%d\n", h, errno);
return -1;
}
if( lk.l_type!=F_UNLCK && (pid==SQLITE_LOCKSTATE_ANYPID || lk.l_pid==pid) ){
#ifdef SQLITE_DEBUG
fprintf(stderr, "%s lock held by %d\n", zType, (int)lk.l_pid);
#endif
return 1;
}
return 0;
}
/*
** This test only works for lock testing on unix/posix VFS.
** Adapted from tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
*/
static int unixLockstatePid(unixFile *pFile, pid_t pid, int *pLockstate){
int hDb; /* File descriptor for the open database file */
int hShm = -1; /* File descriptor for WAL shared-memory file */
ssize_t got; /* Bytes read from header */
int isWal; /* True if in WAL mode */
int nLock = 0; /* Number of locks held */
unsigned char aHdr[100]; /* Database header */
assert(pLockstate);
/* make sure we are dealing with a database file */
hDb = pFile->h;
if( hDb<0 ){
*pLockstate = SQLITE_LOCKSTATE_ERROR;
return SQLITE_ERROR;
}
assert( (strlen(SQLITE_FILE_HEADER)+1)==SQLITE_FILE_HEADER_LEN );
got = pread(hDb, aHdr, 100, 0);
if( got<0 ){
*pLockstate = SQLITE_LOCKSTATE_ERROR;
return SQLITE_ERROR;
}
if( got!=100 || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0 ){
*pLockstate = SQLITE_LOCKSTATE_NOTADB;
return SQLITE_NOTADB;
}
/* First check for an exclusive lock */
nLock += unixIsLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE");
isWal = aHdr[18]==2;
if( nLock==0 && isWal==0 ){
/* Rollback mode */
nLock += unixIsLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2, "PENDING|RESERVED|SHARED");
}
if( nLock==0 && isWal!=0 ){
/* lookup the file descriptor for the shared memory file if we have it open in this process */
unixEnterMutex(); /* Because pFile->pInode is shared across threads */
unixShmNode *pShmNode = pFile->pInode->pShmNode;
if( pShmNode ){
sqlite3_mutex_enter(pShmNode->mutex);
hShm = pShmNode->h;
if( hShm >= 0){
if( unixIsLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ||
unixIsLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){
nLock = 1;
}
}
sqlite3_mutex_leave(pShmNode->mutex);
}
if( hShm<0 ){
/* the shared memory file isn't open in this process space, open our own FD */
char zShm[MAXPATHLEN];
/* WAL mode */
strlcpy(zShm, pFile->zPath, MAXPATHLEN);
strlcat(zShm, "-shm", MAXPATHLEN);
hShm = open(zShm, O_RDONLY, 0);
if( hShm<0 ){
*pLockstate = SQLITE_LOCKSTATE_OFF;
unixLeaveMutex();
return SQLITE_OK;
}
if( unixIsLocked(pid, hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ||
unixIsLocked(pid, hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE") ){
nLock = 1;
}
close(hShm);
}
unixLeaveMutex();
}
if( nLock>0 ){
*pLockstate = SQLITE_LOCKSTATE_ON;
} else {
*pLockstate = SQLITE_LOCKSTATE_OFF;
}
return SQLITE_OK;
}
#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
/*
** Information and control of an open file handle.
*/
@@ -3935,269 +4355,30 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
case SQLITE_SET_LOCKPROXYFILE:
case SQLITE_GET_LOCKPROXYFILE: {
case SQLITE_FCNTL_SET_LOCKPROXYFILE:
case SQLITE_FCNTL_GET_LOCKPROXYFILE: {
return proxyFileControl(id,op,pArg);
}
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
case SQLITE_TRUNCATE_DATABASE: {
unixFile *pFile = (unixFile*)id;
int rc = SQLITE_OK;
void *pLock = NULL;
int flags = 0;
int corruptFileLock = 0;
int isCorrupt = 0;
#if SQLITE_ENABLE_DATA_PROTECTION
flags |= pFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
if( isProxyLockingMode(pFile) ){
flags |= SQLITE_OPEN_AUTOPROXY;
}
#endif
rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
if( rc ){
if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
isCorrupt = 1;
rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptFileLock);
}
if( rc ){
return rc;
}
}
rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
if( rc==SQLITE_OK ){
char jPath[MAXPATHLEN+9];
int zLen = strlcpy(jPath, pFile->zPath, MAXPATHLEN+9);
if( zLen<MAXPATHLEN ){
size_t jLen;
const char extensions[2][9] = { "-wal", "-journal" /*, "-shm" */ };
int j = 0;
for( j=0; j<2; j++ ){
jLen = strlcpy(&jPath[zLen], extensions[j], 9);
if( jLen < 9 ){
int jfd = open(jPath, O_TRUNC);
if( jfd==(-1) ){
if ( errno!=ENOENT ){
perror(jPath);
}
} else {
fsync(jfd);
close(jfd);
}
}
}
}
pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
}
if( isCorrupt ){
sqlite3demo_superunlock_corrupt(id, corruptFileLock);
}else{
sqlite3demo_superunlock(pLock);
}
return rc;
case SQLITE_FCNTL_TRUNCATE_DATABASE: {
return unixTruncateDatabase(pFile, (pArg ? (*(int *)pArg) : 0));
}
case SQLITE_FCNTL_REPLACE_DATABASE: {
return unixReplaceDatabase(pFile, (sqlite3 *)pArg);
}
case SQLITE_FCNTL_LOCKSTATE_PID: {
LockstatePID *pLockstate;
int rc;
case SQLITE_REPLACE_DATABASE: {
unixFile *pFile = (unixFile*)id;
sqlite3 *srcdb = (sqlite3 *)pArg;
Btree *pSrcBtree = NULL;
sqlite3_file *src_file = NULL;
unixFile *pSrcFile = NULL;
char srcWalPath[MAXPATHLEN+5];
int srcWalFD = -1;
int rc = SQLITE_OK;
void *pLock = NULL;
int flags = 0;
sqlite3 *srcdb2 = NULL;
copyfile_state_t s;
int corruptSrcFileLock = 0;
int corruptDstFileLock = 0;
int isSrcCorrupt = 0;
int isDstCorrupt = 0;
if( !sqlite3SafetyCheckOk(srcdb) ){
if( pArg==NULL ){
return SQLITE_MISUSE;
}
#if SQLITE_ENABLE_DATA_PROTECTION
flags |= pFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
if( isProxyLockingMode(pFile) ){
flags |= SQLITE_OPEN_AUTOPROXY;
}
#endif
rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
if( rc ){
if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
isDstCorrupt = 1;
rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptDstFileLock);
}
if( rc ){
return rc;
}
}
/* get the src file descriptor adhering to the db struct access rules
** this code is modeled after sqlite3_file_control() in main.c
*/
sqlite3_mutex_enter(srcdb->mutex);
if( srcdb->nDb>0 ){
pSrcBtree = srcdb->aDb[0].pBt;
}
if( pSrcBtree ){
Pager *pSrcPager;
sqlite3BtreeEnter(pSrcBtree);
pSrcPager = sqlite3BtreePager(pSrcBtree);
assert( pSrcPager!=0 );
src_file = sqlite3PagerFile(pSrcPager);
assert( src_file!=0 );
if( src_file->pMethods ){
int srcFlags = 0;
pSrcFile = (unixFile *)src_file;
/* wal mode db cannot be opened readonly */
if ((pSrcFile->openFlags & O_RDWR) == O_RDWR) {
srcFlags = SQLITE_OPEN_READWRITE;
} else {
srcFlags = SQLITE_OPEN_READONLY;
}
#if SQLITE_ENABLE_DATA_PROTECTION
srcFlags |= pSrcFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
if( isProxyLockingMode(pSrcFile) ){
srcFlags |= SQLITE_OPEN_AUTOPROXY;
}
#endif
rc = sqlite3_open_v2(pSrcFile->zPath, &srcdb2, srcFlags, 0);
if( rc==SQLITE_OK ){
/* start a deferred transaction and read to establish a read lock */
rc = sqlite3_exec(srcdb2, "BEGIN DEFERRED; PRAGMA schema_version", 0, 0, 0);
if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
isSrcCorrupt = 1;
rc = sqlite3demo_superlock_corrupt(src_file, SQLITE_LOCK_SHARED, &corruptSrcFileLock);
}
}
}
}
if( !srcdb2 || pSrcFile==NULL || pSrcFile->h<0){
rc = SQLITE_INTERNAL;
}
if( rc!=SQLITE_OK ){
goto end_replace_database;
}
/* both databases are locked appropriately, copy the src wal journal if
** one exists and then the actual database file
*/
strlcpy(srcWalPath, pSrcFile->zPath, MAXPATHLEN+5);
strlcat(srcWalPath, "-wal", MAXPATHLEN+5);
srcWalFD = open(srcWalPath, O_RDONLY);
if( !(srcWalFD<0) ){
char dstWalPath[MAXPATHLEN+5];
int dstWalFD = -1;
strlcpy(dstWalPath, pFile->zPath, MAXPATHLEN+5);
strlcat(dstWalPath, "-wal", MAXPATHLEN+5);
dstWalFD = open(dstWalPath, O_RDWR|O_CREAT, SQLITE_DEFAULT_FILE_PERMISSIONS);
if( !(dstWalFD<0) ){
s = copyfile_state_alloc();
lseek(srcWalFD, 0, SEEK_SET);
lseek(dstWalFD, 0, SEEK_SET);
if( fcopyfile(srcWalFD, dstWalFD, s, COPYFILE_ALL) ){
int err=errno;
switch(err) {
case ENOMEM:
rc = SQLITE_NOMEM;
break;
default:
pFile->lastErrno = err;
rc = SQLITE_IOERR;
}
}
copyfile_state_free(s);
close(dstWalFD);
}
close(srcWalFD);
}
if( rc==SQLITE_OK ){
/* before we copy, ensure that the file change counter will be modified */
uint32_t srcChange = 0;
uint32_t dstChange = 0;
pread(pSrcFile->h, &srcChange, 4, 24);
pread(pFile->h, &dstChange, 4, 24);
/* copy the actual database */
s = copyfile_state_alloc();
lseek(pSrcFile->h, 0, SEEK_SET);
lseek(pFile->h, 0, SEEK_SET);
if( fcopyfile(pSrcFile->h, pFile->h, s, COPYFILE_ALL) ){
int err=errno;
switch(err) {
case ENOMEM:
rc = SQLITE_NOMEM;
break;
default:
pFile->lastErrno = err;
rc = SQLITE_IOERR;
}
}
copyfile_state_free(s);
if (srcChange == dstChange) {
/* modify the change counter to force page zero to be reloaded */
dstChange ++;
pwrite(pFile->h, &dstChange, 4, 24);
}
}
if( isSrcCorrupt ){
sqlite3demo_superunlock_corrupt(src_file, corruptSrcFileLock);
}else{
/* done with the source db so end the transaction */
sqlite3_exec(srcdb2, "COMMIT", 0, 0, 0);
}
/* zero out any old journal clutter */
if( rc==SQLITE_OK ){
char jPath[MAXPATHLEN+9];
int zLen = strlcpy(jPath, pFile->zPath, MAXPATHLEN+9);
if( zLen<MAXPATHLEN ){
size_t jLen;
const char extensions[2][9] = { "-wal", "-journal" /* "-shm" */ };
int j = (srcWalFD<0)?0:1; /* skip the wal if we replaced it */
for( ; j<2; j++ ){
jLen = strlcpy(&jPath[zLen], extensions[j], 9);
if( jLen < 9 ){
int jfd = open(jPath, O_TRUNC);
if( jfd==(-1) ){
if ( errno!=ENOENT ){
perror(jPath);
}
} else {
fsync(jfd);
close(jfd);
}
}
}
}
pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
}
end_replace_database:
if( pSrcBtree ){
sqlite3_close(srcdb2);
sqlite3BtreeLeave(pSrcBtree);
}
sqlite3_mutex_leave(srcdb->mutex);
if( isDstCorrupt ){
sqlite3demo_superunlock_corrupt(id, corruptDstFileLock);
}else{
sqlite3demo_superunlock(pLock);
}
pLockstate = (LockstatePID *)pArg;
rc = unixLockstatePid(pFile, pLockstate->pid, &(pLockstate->state));
return rc;
}
#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
case SQLITE_FCNTL_SYNC_OMITTED: {
return SQLITE_OK; /* A no-op */
@@ -4526,8 +4707,16 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
}
if( pInode->bProcessLock==0 ){
pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
const char *zRO;
zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm");
if( zRO && sqlite3GetBoolean(zRO) ){
pShmNode->h = robust_open(zShmFilename, O_RDONLY,
(sStat.st_mode & 0777));
pShmNode->isReadonly = 1;
}else{
pShmNode->h = robust_open(zShmFilename, O_RDWR|O_CREAT,
(sStat.st_mode & 0777));
}
if( pShmNode->h<0 ){
const char *zRO;
zRO = sqlite3_uri_parameter(pDbFd->zPath, "readonly_shm");
+9
View File
@@ -1637,6 +1637,15 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
}
return SQLITE_OK;
}
case SQLITE_FCNTL_PERSIST_WAL: {
int bPersist = *(int*)pArg;
if( bPersist<0 ){
*(int*)pArg = pFile->bPersistWal;
}else{
pFile->bPersistWal = bPersist!=0;
}
return SQLITE_OK;
}
case SQLITE_FCNTL_SYNC_OMITTED: {
return SQLITE_OK;
}
+2 -2
View File
@@ -6740,11 +6740,11 @@ static int pagerOpenWal(Pager *pPager){
if( rc==SQLITE_OK ){
#if SQLITE_ENABLE_DATA_PROTECTION
rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode,
pPager->journalSizeLimit, (pPager->vfsFlags & SQLITE_OPEN_FILEPROTECTION_MASK),
pPager->journalSizeLimit, (pPager->vfsFlags & (SQLITE_OPEN_FILEPROTECTION_MASK | SQLITE_OPEN_READONLY)),
&pPager->pWal);
#else
rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode,
pPager->journalSizeLimit, 0, &pPager->pWal);
pPager->journalSizeLimit, (pPager->vfsFlags & SQLITE_OPEN_READONLY), &pPager->pWal);
#endif
}
+21 -11
View File
@@ -767,18 +767,22 @@ struct sqlite3_io_methods {
** That integer is 0 to disable persistent WAL mode or 1 to enable persistent
** WAL mode. If the integer is -1, then it is overwritten with the current
** WAL persistence setting.
**
*/
#define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_GET_LOCKPROXYFILE 2
#define SQLITE_SET_LOCKPROXYFILE 3
#define SQLITE_LAST_ERRNO 4
#define SQLITE_FCNTL_SIZE_HINT 5
#define SQLITE_FCNTL_CHUNK_SIZE 6
#define SQLITE_FCNTL_FILE_POINTER 7
#define SQLITE_FCNTL_SYNC_OMITTED 8
#define SQLITE_FCNTL_WIN32_AV_RETRY 9
#define SQLITE_FCNTL_PERSIST_WAL 10
#define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2
#define SQLITE_FCNTL_SET_LOCKPROXYFILE 3
#define SQLITE_FCNTL_LAST_ERRNO 4
#define SQLITE_FCNTL_SIZE_HINT 5
#define SQLITE_FCNTL_CHUNK_SIZE 6
#define SQLITE_FCNTL_FILE_POINTER 7
#define SQLITE_FCNTL_SYNC_OMITTED 8
#define SQLITE_FCNTL_WIN32_AV_RETRY 9
#define SQLITE_FCNTL_PERSIST_WAL 10
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
/*
** CAPI3REF: Mutex Handle
@@ -3349,6 +3353,12 @@ int sqlite3_step(sqlite3_stmt*);
** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of
** interfaces) then sqlite3_data_count(P) returns 0.
** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
** ^The sqlite3_data_count(P) routine returns 0 if the previous call to
** [sqlite3_step](P) returned [SQLITE_DONE]. ^The sqlite3_data_count(P)
** will return non-zero if previous call to [sqlite3_step](P) returned
** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum]
** where it always returns zero since each step of that multi-step
** pragma returns 0 columns of data.
**
** See also: [sqlite3_column_count()]
*/
+12 -2
View File
@@ -27,17 +27,27 @@
*/
extern int _sqlite3_lockstate(const char *path, pid_t pid);
/*
** Test an open database connection for sqlite locks held by a process ID,
** if a process has an open database connection this will avoid trashing file
** locks by re-using open file descriptors for the database file and support
** files (-shm)
*/
#define SQLITE_FCNTL_LOCKSTATE_PID 103
/*
** Pass the SQLITE_TRUNCATE_DATABASE operation code to sqlite3_file_control()
** to truncate a database and its associated journal file to zero length.
*/
#define SQLITE_TRUNCATE_DATABASE 101
#define SQLITE_FCNTL_TRUNCATE_DATABASE 101
#define SQLITE_TRUNCATE_DATABASE SQLITE_FCNTL_TRUNCATE_DATABASE
/*
** Pass the SQLITE_REPLACE_DATABASE operation code to sqlite3_file_control()
** and a sqlite3 pointer to another open database file to safely copy the
** contents of that database file into the receiving database.
*/
#define SQLITE_REPLACE_DATABASE 102
#define SQLITE_FCNTL_REPLACE_DATABASE 102
#define SQLITE_REPLACE_DATABASE SQLITE_FCNTL_REPLACE_DATABASE
#endif
+25
View File
@@ -3265,4 +3265,29 @@ SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...);
#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
#define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */
#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
/*
** An instance of the following structure is used to hold the process ID
** and return-by-reference lockstate value. The SQLITE_FCNTL_LOCKSTATE_PID
** requires the 4th argument to sqlite3_file_control to be a pointer to an
** instance of LockstatePID initialized with a LockstatePID.pid value equal
** to a process ID to be tested, or the special value SQLITE_LOCKSTATE_ANYPID
** The Lockstate.state value is always set to one of the following values
** when sqlite3_file_control returns:
**
** SQLITE_LOCKSTATE_OFF no active sqlite file locks match the specified pid
** SQLITE_LOCKSTATE_ON active sqlite file locks match the specified pid
** SQLITE_LOCKSTATE_NOTADB path points to a file that is not an sqlite db file
** SQLITE_LOCKSTATE_ERROR path was not vaild or was unreadable
*/
typedef struct LockstatePID LockstatePID;
struct LockstatePID {
pid_t pid; /* Process ID to test */
int state; /* The state of the lock (return value) */
};
#endif
#endif /* _SQLITEINT_H_ */
+8 -5
View File
@@ -4990,17 +4990,21 @@ static int file_control_truncate_test(
Tcl_Obj *CONST objv[] /* Command arguments */
){
sqlite3 *db;
int flags;
int rc;
if( objc!=2 ){
if( objc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
Tcl_GetStringFromObj(objv[0], 0), " DB FLAGS", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
return TCL_ERROR;
}
rc = sqlite3_file_control(db, NULL, SQLITE_TRUNCATE_DATABASE, 0);
if( Tcl_GetIntFromObj(interp, objv[2], &flags) ){
return TCL_ERROR;
}
rc = sqlite3_file_control(db, NULL, SQLITE_TRUNCATE_DATABASE, &flags);
if( rc ){
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
return TCL_ERROR;
@@ -5205,7 +5209,6 @@ static int path_is_local(
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
sqlite3 *db;
const char *zPath;
int nPath;
@@ -5247,7 +5250,6 @@ static int path_is_dos(
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
sqlite3 *db;
const char *zPath;
int nPath;
@@ -6173,6 +6175,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "file_control_sizehint_test", file_control_sizehint_test, 0 },
{ "file_control_win32_av_retry", file_control_win32_av_retry, 0 },
{ "file_control_persist_wal", file_control_persist_wal, 0 },
{ "file_control_persist_wal", file_control_persist_wal, 0 },
{ "sqlite3_vfs_list", vfs_list, 0 },
{ "sqlite3_create_function_v2", test_create_function_v2, 0 },
{ "path_is_local", path_is_local, 0 },
+5 -1
View File
@@ -1142,7 +1142,7 @@ int sqlite3VdbeList(
sqlite3 *db = p->db; /* The database connection */
int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
Mem *pMem = p->pResultSet = &p->aMem[1]; /* First Mem of result set */
Mem *pMem = &p->aMem[1]; /* First Mem of result set */
assert( p->explain );
assert( p->magic==VDBE_MAGIC_RUN );
@@ -1153,6 +1153,7 @@ int sqlite3VdbeList(
** sqlite3_column_text16(), causing a translation to UTF-16 encoding.
*/
releaseMemArray(pMem, 8);
p->pResultSet = 0;
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
@@ -1307,6 +1308,7 @@ int sqlite3VdbeList(
}
p->nResColumn = 8 - 4*(p->explain-1);
p->pResultSet = &p->aMem[1];
p->rc = SQLITE_OK;
rc = SQLITE_ROW;
}
@@ -1511,6 +1513,8 @@ void sqlite3VdbeMakeReady(
assert( EIGHT_BYTE_ALIGNMENT(zCsr) );
p->expired = 0;
p->expired = 0;
/* Memory for registers, parameters, cursor, etc, is allocated in two
** passes. On the first pass, we try to reuse unused space at the
** end of the opcode array. If we are unable to satisfy all memory
+9 -2
View File
@@ -1285,7 +1285,11 @@ int sqlite3WalOpen(
pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
/* Open file handle on the write-ahead log file. */
vfsFlags = flags | (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
if( flags&SQLITE_OPEN_READONLY ){
vfsFlags = flags | SQLITE_OPEN_WAL;
} else {
vfsFlags = flags | (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
}
rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, vfsFlags, &vfsFlags);
if( rc==SQLITE_OK && vfsFlags&SQLITE_OPEN_READONLY ){
pRet->readOnly = WAL_RDONLY;
@@ -1866,6 +1870,9 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
** reordering the reads and writes.
*/
aHdr = walIndexHdr(pWal);
if( aHdr==NULL ){
return 1; /* Shouldn't be getting NULL from walIndexHdr, but we are */
}
memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
walShmBarrier(pWal);
memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
@@ -2050,7 +2057,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
*/
if( cnt>5 ){
int nDelay = 1; /* Pause time in microseconds */
if( cnt>100 ){
if( cnt>500 ){
VVA_ONLY( pWal->lockError = 1; )
return SQLITE_PROTOCOL;
}