SQLite

Check-in [34f0efa2b1]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merging local changes to apple-osx
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | apple-osx
Files: files | file ages | folders
SHA1: 34f0efa2b12e8eb09331768b1524a076baeb34ea
User & Date: adam 2011-06-24 20:47:06.827
Context
2011-06-24
21:47
Fix the build. (check-in: 97729542d5 user: drh tags: apple-osx)
20:47
Merging local changes to apple-osx (check-in: 34f0efa2b1 user: adam tags: apple-osx)
2011-06-23
17:42
Pull the last-minute fixes for 3.7.7 into the apple-osx branch. (check-in: 2d4458af59 user: drh tags: apple-osx)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/btree.c.
64
65
66
67
68
69
70





71
72

73
74
75
76
77
78
79
** Enable or disable the shared pager and schema features.
**
** This routine has no effect on existing database connections.
** The shared cache setting effects only future calls to
** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
*/
int sqlite3_enable_shared_cache(int enable){





  sqlite3GlobalConfig.sharedCacheEnabled = enable;
  return SQLITE_OK;

}
#endif



#ifdef SQLITE_OMIT_SHARED_CACHE
  /*







>
>
>
>
>


>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
** Enable or disable the shared pager and schema features.
**
** This routine has no effect on existing database connections.
** The shared cache setting effects only future calls to
** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
*/
int sqlite3_enable_shared_cache(int enable){
#if defined(__APPLE__) && !defined(SQLITE_TEST) && !defined(TH3_COMPATIBILITY)
  /* Enable global shared cache function for debugging and unit tests, 
  ** but not for release */
  return SQLITE_MISUSE;
#else
  sqlite3GlobalConfig.sharedCacheEnabled = enable;
  return SQLITE_OK;
#endif
}
#endif



#ifdef SQLITE_OMIT_SHARED_CACHE
  /*
2346
2347
2348
2349
2350
2351
2352












2353
2354
2355
2356
2357
2358
2359
    */
    if( page1[19]==2 && pBt->doNotUseWAL==0 ){
      int isOpen = 0;
      rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
      if( rc!=SQLITE_OK ){
        goto page1_init_failed;
      }else if( isOpen==0 ){












        releasePage(pPage1);
        return SQLITE_OK;
      }
      rc = SQLITE_NOTADB;
    }
#endif








>
>
>
>
>
>
>
>
>
>
>
>







2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
    */
    if( page1[19]==2 && pBt->doNotUseWAL==0 ){
      int isOpen = 0;
      rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
      if( rc!=SQLITE_OK ){
        goto page1_init_failed;
      }else if( isOpen==0 ){
#ifdef SQLITE_DEFAULT_WAL_SAFETYLEVEL
        /* Default to specified safety_level for WAL mode */
        if( pBt->db!=0 && pBt->db->aDb!=0 ){
          sqlite3 *db = pBt->db;
          if( db->aDb[0].safety_level != SQLITE_DEFAULT_WAL_SAFETYLEVEL) {
            db->aDb[0].safety_level = SQLITE_DEFAULT_WAL_SAFETYLEVEL;
            sqlite3PagerSetSafetyLevel(pBt->pPager, SQLITE_DEFAULT_WAL_SAFETYLEVEL, 
                                       (db->flags&SQLITE_FullFSync)!=0,
                                       (db->flags&SQLITE_CkptFullFSync)!=0);
          }
        }
#endif
        releasePage(pPage1);
        return SQLITE_OK;
      }
      rc = SQLITE_NOTADB;
    }
#endif

Changes to src/main.c.
1793
1794
1795
1796
1797
1798
1799


1800
1801
1802



1803
1804
1805
1806
1807
1808
1809
      newLimit = aHardLimit[limitId];  /* IMP: R-51463-25634 */
    }
    db->aLimit[limitId] = newLimit;
  }
  return oldLimit;                     /* IMP: R-53341-35419 */
}
#if defined(SQLITE_ENABLE_AUTO_PROFILE)


static void profile_sql(void *aux, const char *sql, u64 ns) {
#pragma unused(aux)
	fprintf(stderr, "Query: %s\n Execution Time: %llu ms\n", sql, ns / 1000000);



}
#endif

/*
** This function is used to parse both URIs and non-URI filenames passed by the
** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database
** URIs specified as part of ATTACH statements.







>
>
|


>
>
>







1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
      newLimit = aHardLimit[limitId];  /* IMP: R-51463-25634 */
    }
    db->aLimit[limitId] = newLimit;
  }
  return oldLimit;                     /* IMP: R-53341-35419 */
}
#if defined(SQLITE_ENABLE_AUTO_PROFILE)
void _sqlite_auto_profile(void *aux, const char *sql, u64 ns);
void _sqlite_auto_trace(void *aux, const char *sql);
void _sqlite_auto_profile(void *aux, const char *sql, u64 ns) {
#pragma unused(aux)
	fprintf(stderr, "Query: %s\n Execution Time: %llu ms\n", sql, ns / 1000000);
}
void _sqlite_auto_trace(void *aux, const char *sql) {
	fprintf(stderr, "TraceSQL(%p): %s\n", aux, sql);
}
#endif

/*
** This function is used to parse both URIs and non-URI filenames passed by the
** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database
** URIs specified as part of ATTACH statements.
2131
2132
2133
2134
2135
2136
2137



2138
2139
2140
2141
2142
2143
2144

  assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
  memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
  db->autoCommit = 1;
  db->nextAutovac = -1;
  db->nextPagesize = 0;
  db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger



#if SQLITE_DEFAULT_FILE_FORMAT<4
                 | SQLITE_LegacyFileFmt
#endif
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
                 | SQLITE_LoadExtension
#endif
#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS







>
>
>







2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152

  assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
  memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
  db->autoCommit = 1;
  db->nextAutovac = -1;
  db->nextPagesize = 0;
  db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger
#if SQLITE_DEFAULT_CKPTFULLFSYNC
                 | SQLITE_CkptFullFSync
#endif
#if SQLITE_DEFAULT_FILE_FORMAT<4
                 | SQLITE_LegacyFileFmt
#endif
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
                 | SQLITE_LoadExtension
#endif
#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS
2290
2291
2292
2293
2294
2295
2296

2297
2298
2299



2300
2301
2302
2303
2304
2305
2306
    db = 0;
  }else if( rc!=SQLITE_OK ){
    db->magic = SQLITE_MAGIC_SICK;
  }
#if defined(SQLITE_ENABLE_AUTO_PROFILE)
  if( db && !rc ){
    char *envprofile = getenv("SQLITE_AUTO_PROFILE");

    
    if( envprofile!=NULL ){
      sqlite3_profile(db, profile_sql, NULL);



    }
  }
#endif
  *ppDb = db;
#ifdef SQLITE_ENABLE_SQLRR
  SRRecOpen(db, zFilename, flags);
#endif







>


|
>
>
>







2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
    db = 0;
  }else if( rc!=SQLITE_OK ){
    db->magic = SQLITE_MAGIC_SICK;
  }
#if defined(SQLITE_ENABLE_AUTO_PROFILE)
  if( db && !rc ){
    char *envprofile = getenv("SQLITE_AUTO_PROFILE");
    char *envtrace = getenv("SQLITE_AUTO_TRACE");
    
    if( envprofile!=NULL ){
      sqlite3_profile(db, _sqlite_auto_profile, db);
    }
    if( envtrace!=NULL ){
      sqlite3_trace(db, _sqlite_auto_trace, db);
    }
  }
#endif
  *ppDb = db;
#ifdef SQLITE_ENABLE_SQLRR
  SRRecOpen(db, zFilename, flags);
#endif
2962
2963
2964
2965
2966
2967
2968














































































































































    int x = strcmp(zFilename, zParam);
    zFilename += sqlite3Strlen30(zFilename) + 1;
    if( x==0 ) return zFilename;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return 0;
}





















































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
    int x = strcmp(zFilename, zParam);
    zFilename += sqlite3Strlen30(zFilename) + 1;
    if( x==0 ) return zFilename;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return 0;
}

#if (SQLITE_ENABLE_APPLE_SPI>0)
#define SQLITE_FILE_HEADER_LEN 16
#include <fcntl.h>
#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 */
  
  /* 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;
  }
  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;
}

#endif /* SQLITE_ENABLE_APPLE_SPI */
Changes to src/os.c.
127
128
129
130
131
132
133

134
135
136
137
138





139
140
141
142
143
144
145
146
  sqlite3_vfs *pVfs, 
  const char *zPath, 
  sqlite3_file *pFile, 
  int flags, 
  int *pFlagsOut
){
  int rc;

  DO_OS_MALLOC_TEST(0);
  /* 0x87f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
  ** down into the VFS layer.  Some SQLITE_OPEN_ flags (for example,
  ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
  ** reaching the VFS. */





  rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f3f, pFlagsOut);
  assert( rc==SQLITE_OK || pFile->pMethods==0 );
  return rc;
}
int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  return pVfs->xDelete(pVfs, zPath, dirSync);
}
int sqlite3OsAccess(







>





>
>
>
>
>
|







127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  sqlite3_vfs *pVfs, 
  const char *zPath, 
  sqlite3_file *pFile, 
  int flags, 
  int *pFlagsOut
){
  int rc;
  int openFlags;
  DO_OS_MALLOC_TEST(0);
  /* 0x87f3f is a mask of SQLITE_OPEN_ flags that are valid to be passed
  ** down into the VFS layer.  Some SQLITE_OPEN_ flags (for example,
  ** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
  ** reaching the VFS. */
#if SQLITE_ENABLE_DATA_PROTECTION
  openFlags = flags & (0x87f3f | SQLITE_OPEN_FILEPROTECTION_MASK);
#else
  openFlags = flags & 0x87f3f;
#endif
  rc = pVfs->xOpen(pVfs, zPath, pFile, openFlags, pFlagsOut);
  assert( rc==SQLITE_OK || pFile->pMethods==0 );
  return rc;
}
int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  return pVfs->xDelete(pVfs, zPath, dirSync);
}
int sqlite3OsAccess(
Changes to src/os_unix.c.
121
122
123
124
125
126
127





128
129
130
131
132
133
134
#include <errno.h>
#ifndef SQLITE_OMIT_WAL
#include <sys/mman.h>
#endif

#if SQLITE_ENABLE_LOCKING_STYLE
# include <sys/ioctl.h>





# if OS_VXWORKS
#  include <semaphore.h>
#  include <limits.h>
# else
#  include <sys/file.h>
#  include <sys/param.h>
# endif







>
>
>
>
>







121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <errno.h>
#ifndef SQLITE_OMIT_WAL
#include <sys/mman.h>
#endif

#if SQLITE_ENABLE_LOCKING_STYLE
# include <sys/ioctl.h>
# include <uuid/uuid.h>
# if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
                            (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
#  define HAVE_GETHOSTUUID 1
# endif
# if OS_VXWORKS
#  include <semaphore.h>
#  include <limits.h>
# else
#  include <sys/file.h>
#  include <sys/param.h>
# endif
216
217
218
219
220
221
222



223
224
225
226
227
228
229
  UnixUnusedFd *pUnused;              /* Pre-allocated UnixUnusedFd */
  const char *zPath;                  /* Name of the file */
  unixShm *pShm;                      /* Shared memory segment information */
  int szChunk;                        /* Configured by FCNTL_CHUNK_SIZE */
#if SQLITE_ENABLE_LOCKING_STYLE
  int openFlags;                      /* The flags specified at open() */
#endif



#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
  unsigned fsFlags;                   /* cached details from statfs() */
#endif
#if OS_VXWORKS
  int isDelete;                       /* Delete on close if true */
  struct vxworksFileId *pId;          /* Unique file ID */
#endif







>
>
>







221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  UnixUnusedFd *pUnused;              /* Pre-allocated UnixUnusedFd */
  const char *zPath;                  /* Name of the file */
  unixShm *pShm;                      /* Shared memory segment information */
  int szChunk;                        /* Configured by FCNTL_CHUNK_SIZE */
#if SQLITE_ENABLE_LOCKING_STYLE
  int openFlags;                      /* The flags specified at open() */
#endif
#if SQLITE_ENABLE_DATA_PROTECTION
  int protFlags;                      /* Data protection flags from unixOpen */
#endif
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
  unsigned fsFlags;                   /* cached details from statfs() */
#endif
#if OS_VXWORKS
  int isDelete;                       /* Delete on close if true */
  struct vxworksFileId *pId;          /* Unique file ID */
#endif
280
281
282
283
284
285
286























































































































































































































































































287
288
289
290
291
292
293
** testing and debugging only.
*/
#if SQLITE_THREADSAFE
#define threadid pthread_self()
#else
#define threadid 0
#endif
























































































































































































































































































/*
** Different Unix systems declare open() in different ways.  Same use
** open(const char*,int,mode_t).  Others use open(const char*,int,...).
** The difference is important when using a pointer to the function.
**
** The safest way to deal with the problem is to always use this wrapper







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
** testing and debugging only.
*/
#if SQLITE_THREADSAFE
#define threadid pthread_self()
#else
#define threadid 0
#endif

#ifdef __APPLE__
#define SQLITE_ENABLE_SUPERLOCK 1
#endif

#if SQLITE_ENABLE_SUPERLOCK
#include "sqlite3.h"
#include <string.h>               /* memset(), strlen() */
#include <assert.h>               /* assert() */

/*
** A structure to collect a busy-handler callback and argument and a count
** of the number of times it has been invoked.
*/
struct SuperlockBusy {
  int (*xBusy)(void*,int);        /* Pointer to busy-handler function */
  void *pBusyArg;                 /* First arg to pass to xBusy */
  int nBusy;                      /* Number of times xBusy has been invoked */
};
typedef struct SuperlockBusy SuperlockBusy;

/*
** An instance of the following structure is allocated for each active
** superlock. The opaque handle returned by sqlite3demo_superlock() is
** actually a pointer to an instance of this structure.
*/
struct Superlock {
  sqlite3 *db;                    /* Database handle used to lock db */
  int bWal;                       /* True if db is a WAL database */
};
typedef struct Superlock Superlock;

/*
** The pCtx pointer passed to this function is actually a pointer to a
** SuperlockBusy structure. Invoke the busy-handler function encapsulated
** by the structure and return the result.
*/
static int superlockBusyHandler(void *pCtx, int UNUSED){
  SuperlockBusy *pBusy = (SuperlockBusy *)pCtx;
  if( pBusy->xBusy==0 ) return 0;
  return pBusy->xBusy(pBusy->pBusyArg, pBusy->nBusy++);
}

/*
** This function is used to determine if the main database file for 
** connection db is open in WAL mode or not. If no error occurs and the
** database file is in WAL mode, set *pbWal to true and return SQLITE_OK.
** If it is not in WAL mode, set *pbWal to false.
**
** If an error occurs, return an SQLite error code. The value of *pbWal
** is undefined in this case.
*/
static int superlockIsWal(Superlock *pLock){
  int rc;                         /* Return Code */
  sqlite3_stmt *pStmt;            /* Compiled PRAGMA journal_mode statement */

  rc = sqlite3_prepare(pLock->db, "PRAGMA main.journal_mode", -1, &pStmt, 0);
  if( rc!=SQLITE_OK ) return rc;

  pLock->bWal = 0;
  if( SQLITE_ROW==sqlite3_step(pStmt) ){
    const char *zMode = (const char *)sqlite3_column_text(pStmt, 0);
    if( zMode && strlen(zMode)==3 && sqlite3_strnicmp("wal", zMode, 3)==0 ){
      pLock->bWal = 1;
    }
  }

  return sqlite3_finalize(pStmt);
}

/*
** Obtain an exclusive shm-lock on nByte bytes starting at offset idx
** of the file fd. If the lock cannot be obtained immediately, invoke
** the busy-handler until either it is obtained or the busy-handler
** callback returns 0.
*/
static int superlockShmLock(
  sqlite3_file *fd,               /* Database file handle */
  int idx,                        /* Offset of shm-lock to obtain */
  int nByte,                      /* Number of consective bytes to lock */
  SuperlockBusy *pBusy            /* Busy-handler wrapper object */
){
  int rc;
  int (*xShmLock)(sqlite3_file*, int, int, int) = fd->pMethods->xShmLock;
  do {
    rc = xShmLock(fd, idx, nByte, SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE);
  }while( rc==SQLITE_BUSY && superlockBusyHandler((void *)pBusy, 0) );
  return rc;
}

/*
** Obtain the extra locks on the database file required for WAL databases.
** Invoke the supplied busy-handler as required.
*/
static int superlockWalLock(
  sqlite3 *db,                    /* Database handle open on WAL database */
  SuperlockBusy *pBusy            /* Busy handler wrapper object */
){
  int rc;                         /* Return code */
  sqlite3_file *fd = 0;           /* Main database file handle */
  void volatile *p = 0;           /* Pointer to first page of shared memory */

  /* Obtain a pointer to the sqlite3_file object open on the main db file. */
  rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
  if( rc!=SQLITE_OK ) return rc;

  /* Obtain the "recovery" lock. Normally, this lock is only obtained by
  ** clients running database recovery.  
  */
  rc = superlockShmLock(fd, 2, 1, pBusy);
  if( rc!=SQLITE_OK ) return rc;

  /* Zero the start of the first shared-memory page. This means that any
  ** clients that open read or write transactions from this point on will
  ** have to run recovery before proceeding. Since they need the "recovery"
  ** lock that this process is holding to do that, no new read or write
  ** transactions may now be opened. Nor can a checkpoint be run, for the
  ** same reason.
  */
  rc = fd->pMethods->xShmMap(fd, 0, 32*1024, 1, &p);
  if( rc!=SQLITE_OK ) return rc;
  memset((void *)p, 0, 32);

  /* Obtain exclusive locks on all the "read-lock" slots. Once these locks
  ** are held, it is guaranteed that there are no active reader, writer or 
  ** checkpointer clients.
  */
  rc = superlockShmLock(fd, 3, SQLITE_SHM_NLOCK-3, pBusy);
  return rc;
}

/*
** Release a superlock held on a database file. The argument passed to 
** this function must have been obtained from a successful call to
** sqlite3demo_superlock().
*/
static void sqlite3demo_superunlock(void *pLock){
  Superlock *p = (Superlock *)pLock;
  if( p->bWal ){
    int rc;                         /* Return code */
    int flags = SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE;
    sqlite3_file *fd = 0;
    rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
    if( rc==SQLITE_OK ){
      fd->pMethods->xShmLock(fd, 2, 1, flags);
      fd->pMethods->xShmLock(fd, 3, SQLITE_SHM_NLOCK-3, flags);
    }
  }
  sqlite3_close(p->db);
  sqlite3_free(p);
}

/*
** Obtain a superlock on the database file identified by zPath, using the
** locking primitives provided by VFS zVfs. If successful, SQLITE_OK is
** returned and output variable *ppLock is populated with an opaque handle
** that may be used with sqlite3demo_superunlock() to release the lock.
**
** If an error occurs, *ppLock is set to 0 and an SQLite error code 
** (e.g. SQLITE_BUSY) is returned.
**
** If a required lock cannot be obtained immediately and the xBusy parameter
** to this function is not NULL, then xBusy is invoked in the same way
** as a busy-handler registered with SQLite (using sqlite3_busy_handler())
** until either the lock can be obtained or the busy-handler function returns
** 0 (indicating "give up").
*/
static int sqlite3demo_superlock(
  const char *zPath,              /* Path to database file to lock */
  const char *zVfs,               /* VFS to use to access database file */
  int flags,                      /* Additional flags to pass to sqlite3_open_v2 */
  int (*xBusy)(void*,int),        /* Busy handler callback */
  void *pBusyArg,                 /* Context arg for busy handler */
  void **ppLock                   /* OUT: Context to pass to superunlock() */
){
  SuperlockBusy busy = {0, 0, 0}; /* Busy handler wrapper object */
  int rc;                         /* Return code */
  Superlock *pLock;

  pLock = sqlite3_malloc(sizeof(Superlock));
  if( !pLock ) return SQLITE_NOMEM;
  memset(pLock, 0, sizeof(Superlock));

  /* Open a database handle on the file to superlock. */
  rc = sqlite3_open_v2(
      zPath, &pLock->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|flags, zVfs
  );

  /* Install a busy-handler and execute a BEGIN EXCLUSIVE. If this is not
  ** a WAL database, this is all we need to do.  
  **
  ** A wrapper function is used to invoke the busy-handler instead of
  ** registering the busy-handler function supplied by the user directly
  ** with SQLite. This is because the same busy-handler function may be
  ** invoked directly later on when attempting to obtain the extra locks
  ** required in WAL mode. By using the wrapper, we are able to guarantee
  ** that the "nBusy" integer parameter passed to the users busy-handler
  ** represents the total number of busy-handler invocations made within
  ** this call to sqlite3demo_superlock(), including any made during the
  ** "BEGIN EXCLUSIVE".
  */
  if( rc==SQLITE_OK ){
    busy.xBusy = xBusy;
    busy.pBusyArg = pBusyArg;
    sqlite3_busy_handler(pLock->db, superlockBusyHandler, (void *)&busy);
    rc = sqlite3_exec(pLock->db, "BEGIN EXCLUSIVE", 0, 0, 0);
  }

  /* If the BEGIN EXCLUSIVE was executed successfully and this is a WAL
  ** database, call superlockWalLock() to obtain the extra locks required
  ** to prevent readers, writers and/or checkpointers from accessing the
  ** db while this process is holding the superlock.
  **
  ** Before attempting any WAL locks, commit the transaction started above
  ** to drop the WAL read and write locks currently held. Otherwise, the
  ** new WAL locks may conflict with the old.
  */
  if( rc==SQLITE_OK ){
    if( SQLITE_OK==(rc = superlockIsWal(pLock)) && pLock->bWal ){
      rc = sqlite3_exec(pLock->db, "COMMIT", 0, 0, 0);
      if( rc==SQLITE_OK ){
        rc = superlockWalLock(pLock->db, &busy);
      }
    }
  }

  if( rc!=SQLITE_OK ){
    sqlite3demo_superunlock(pLock);
    *ppLock = 0;
  }else{
    *ppLock = pLock;
  }

  return rc;
}

/* A corrupt DB won't work with the sql-based locking attempt, grab an 
** exclusive lock and return SQLITE_OK or SQLITE_BUSY if the lock fails 
** returns the current lock level held on sqlite3_file
*/
static int sqlite3demo_superlock_corrupt(sqlite3_file *id, int eTargetFileLock, int *pFileLock) {
  unixFile *pFile = (unixFile*)id;
  int eFileLock = pFile->eFileLock;
  int rc = SQLITE_OK;
  
  if( eFileLock<eTargetFileLock ){
    rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED);
  }
  if( !rc && eFileLock<eTargetFileLock ){
    rc = pFile->pMethod->xLock(id, SQLITE_LOCK_EXCLUSIVE);
  }
  if( rc ){
    if( pFile->eFileLock > eFileLock ){
      pFile->pMethod->xUnlock(id, eFileLock);
    }
    return rc;
  }
  if (pFileLock) {
    *pFileLock = eFileLock;
  }
  return SQLITE_OK;
}

static int sqlite3demo_superunlock_corrupt(sqlite3_file *id, int eFileLock) {
  unixFile *pFile = (unixFile*)id;
  int rc = SQLITE_OK;
  
  if( pFile->eFileLock > eFileLock ){
    rc = pFile->pMethod->xUnlock(id, SQLITE_LOCK_SHARED);
  }
  if( pFile->eFileLock > eFileLock ){
    int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_NONE);
    if (!rc) rc = unlockRC;
  }
  return rc;
}

#endif /* SQLITE_ENABLE_SUPERLOCK */


/*
** Different Unix systems declare open() in different ways.  Same use
** open(const char*,int,mode_t).  Others use open(const char*,int,...).
** The difference is important when using a pointer to the function.
**
** The safest way to deal with the problem is to always use this wrapper
1058
1059
1060
1061
1062
1063
1064










1065
1066

1067
1068
1069
1070
1071
1072
1073
*/ 
static void closePendingFds(unixFile *pFile){
  unixInodeInfo *pInode = pFile->pInode;
  UnixUnusedFd *p;
  UnixUnusedFd *pNext;
  for(p=pInode->pUnused; p; p=pNext){
    pNext = p->pNext;










    robust_close(pFile, p->fd, __LINE__);
    sqlite3_free(p);

  }
  pInode->pUnused = 0;
}

/*
** Release a unixInodeInfo structure previously allocated by findInodeInfo().
**







>
>
>
>
>
>
>
>
>
>


>







1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
*/ 
static void closePendingFds(unixFile *pFile){
  unixInodeInfo *pInode = pFile->pInode;
  UnixUnusedFd *p;
  UnixUnusedFd *pNext;
  for(p=pInode->pUnused; p; p=pNext){
    pNext = p->pNext;
#if OSCLOSE_CHECK_CLOSE_IOERR
    if( close(p->fd) ){
      pFile->lastErrno = errno;
      rc = SQLITE_IOERR_CLOSE;
      p->pNext = pError;
      pError = p;
    }else{
      sqlite3_free(p);
    }
#else
    robust_close(pFile, p->fd, __LINE__);
    sqlite3_free(p);
#endif
  }
  pInode->pUnused = 0;
}

/*
** Release a unixInodeInfo structure previously allocated by findInodeInfo().
**
1216
1217
1218
1219
1220
1221
1222





1223
1224

1225
1226
1227
1228
1229
1230
1231
  if( !reserved && !pFile->pInode->bProcessLock ){
    struct flock lock;
    lock.l_whence = SEEK_SET;
    lock.l_start = RESERVED_BYTE;
    lock.l_len = 1;
    lock.l_type = F_WRLCK;
    if( osFcntl(pFile->h, F_GETLK, &lock) ){





      rc = SQLITE_IOERR_CHECKRESERVEDLOCK;
      pFile->lastErrno = errno;

    } else if( lock.l_type!=F_UNLCK ){
      reserved = 1;
    }
  }
#endif
  
  unixLeaveMutex();







>
>
>
>
>


>







1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
  if( !reserved && !pFile->pInode->bProcessLock ){
    struct flock lock;
    lock.l_whence = SEEK_SET;
    lock.l_start = RESERVED_BYTE;
    lock.l_len = 1;
    lock.l_type = F_WRLCK;
    if( osFcntl(pFile->h, F_GETLK, &lock) ){
#if OSLOCKING_CHECK_BUSY_IOERR
      int tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
      pFile->lastErrno = tErrno;
#else
      rc = SQLITE_IOERR_CHECKRESERVEDLOCK;
      pFile->lastErrno = errno;
#endif
    } else if( lock.l_type!=F_UNLCK ){
      reserved = 1;
    }
  }
#endif
  
  unixLeaveMutex();
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
      || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
  ){
    lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
    lock.l_start = PENDING_BYTE;
    if( unixFileLock(pFile, &lock) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( rc!=SQLITE_BUSY ){
        pFile->lastErrno = tErrno;
      }
      goto end_lock;
    }
  }









|







1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
      || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
  ){
    lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
    lock.l_start = PENDING_BYTE;
    if( unixFileLock(pFile, &lock) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( IS_LOCK_ERROR(rc) ){
        pFile->lastErrno = tErrno;
      }
      goto end_lock;
    }
  }


1447
1448
1449
1450
1451
1452
1453



1454

1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
    /* Drop the temporary PENDING lock */
    lock.l_start = PENDING_BYTE;
    lock.l_len = 1L;
    lock.l_type = F_UNLCK;
    if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
      /* This could happen with a network mount */
      tErrno = errno;



      rc = SQLITE_IOERR_UNLOCK; 

    }

    if( rc ){
      if( rc!=SQLITE_BUSY ){
        pFile->lastErrno = tErrno;
      }
      goto end_lock;
    }else{
      pFile->eFileLock = SHARED_LOCK;
      pInode->nLock++;
      pInode->nShared = 1;







>
>
>

>



|







1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
    /* Drop the temporary PENDING lock */
    lock.l_start = PENDING_BYTE;
    lock.l_len = 1L;
    lock.l_type = F_UNLCK;
    if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
      /* This could happen with a network mount */
      tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); 
#else
      rc = SQLITE_IOERR_UNLOCK; 
#endif
    }

    if( rc ){
      if( IS_LOCK_ERROR(rc) ){
        pFile->lastErrno = tErrno;
      }
      goto end_lock;
    }else{
      pFile->eFileLock = SHARED_LOCK;
      pInode->nLock++;
      pInode->nShared = 1;
1618
1619
1620
1621
1622
1623
1624



1625

1626
1627
1628
1629
1630
1631
1632
        
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock(pFile, &lock)==(-1) ){
          tErrno = errno;



          rc = SQLITE_IOERR_UNLOCK;

          if( IS_LOCK_ERROR(rc) ){
            pFile->lastErrno = tErrno;
          }
          goto end_unlock;
        }
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;







>
>
>

>







1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
        
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock(pFile, &lock)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
            pFile->lastErrno = tErrno;
          }
          goto end_unlock;
        }
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
1642
1643
1644
1645
1646
1647
1648



1649

1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662







1663
1664
1665
1666
1667
1668
1669
1670

1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681







1682
1683

1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702







1703
1704

1705
1706
1707
1708
1709
1710
1711
        }
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST+divSize;
        lock.l_len = SHARED_SIZE-divSize;
        if( unixFileLock(pFile, &lock)==(-1) ){
          tErrno = errno;



          rc = SQLITE_IOERR_UNLOCK;

          if( IS_LOCK_ERROR(rc) ){
            pFile->lastErrno = tErrno;
          }
          goto end_unlock;
        }
      }else
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
      {
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = SHARED_SIZE;
        if( unixFileLock(pFile, &lock) ){







          /* In theory, the call to unixFileLock() cannot fail because another
          ** process is holding an incompatible lock. If it does, this 
          ** indicates that the other process is not following the locking
          ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning
          ** SQLITE_BUSY would confuse the upper layer (in practice it causes 
          ** an assert to fail). */ 
          rc = SQLITE_IOERR_RDLOCK;
          pFile->lastErrno = errno;

          goto end_unlock;
        }
      }
    }
    lock.l_type = F_UNLCK;
    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 ){
      pInode->eFileLock = SHARED_LOCK;
    }else{







      rc = SQLITE_IOERR_UNLOCK;
      pFile->lastErrno = errno;

      goto end_unlock;
    }
  }
  if( eFileLock==NO_LOCK ){
    /* Decrement the shared lock counter.  Release the lock using an
    ** OS call only when all threads in this same process have released
    ** the lock.
    */
    pInode->nShared--;
    if( pInode->nShared==0 ){
      lock.l_type = F_UNLCK;
      lock.l_whence = SEEK_SET;
      lock.l_start = lock.l_len = 0L;
      SimulateIOErrorBenign(1);
      SimulateIOError( h=(-1) )
      SimulateIOErrorBenign(0);
      if( unixFileLock(pFile, &lock)==0 ){
        pInode->eFileLock = NO_LOCK;
      }else{







        rc = SQLITE_IOERR_UNLOCK;
	pFile->lastErrno = errno;

        pInode->eFileLock = NO_LOCK;
        pFile->eFileLock = NO_LOCK;
      }
    }

    /* Decrement the count of locks against this same file.  When the
    ** count reaches zero, close any other file descriptors whose close







>
>
>

>













>
>
>
>
>
>
>








>











>
>
>
>
>
>
>


>



















>
>
>
>
>
>
>

|
>







1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
        }
        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST+divSize;
        lock.l_len = SHARED_SIZE-divSize;
        if( unixFileLock(pFile, &lock)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
            pFile->lastErrno = tErrno;
          }
          goto end_unlock;
        }
      }else
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
      {
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = SHARED_SIZE;
        if( unixFileLock(pFile, &lock) ){
#if OSLOCKING_CHECK_BUSY_IOERR
          tErrno = errno;
          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 
          ** indicates that the other process is not following the locking
          ** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning
          ** SQLITE_BUSY would confuse the upper layer (in practice it causes 
          ** an assert to fail). */ 
          rc = SQLITE_IOERR_RDLOCK;
          pFile->lastErrno = errno;
#endif
          goto end_unlock;
        }
      }
    }
    lock.l_type = F_UNLCK;
    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 ){
      pInode->eFileLock = SHARED_LOCK;
    }else{
#if OSLOCKING_CHECK_BUSY_IOERR
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
      if( IS_LOCK_ERROR(rc) ){
        pFile->lastErrno = tErrno;
      }
#else
      rc = SQLITE_IOERR_UNLOCK;
      pFile->lastErrno = errno;
#endif
      goto end_unlock;
    }
  }
  if( eFileLock==NO_LOCK ){
    /* Decrement the shared lock counter.  Release the lock using an
    ** OS call only when all threads in this same process have released
    ** the lock.
    */
    pInode->nShared--;
    if( pInode->nShared==0 ){
      lock.l_type = F_UNLCK;
      lock.l_whence = SEEK_SET;
      lock.l_start = lock.l_len = 0L;
      SimulateIOErrorBenign(1);
      SimulateIOError( h=(-1) )
      SimulateIOErrorBenign(0);
      if( unixFileLock(pFile, &lock)==0 ){
        pInode->eFileLock = NO_LOCK;
      }else{
#if OSLOCKING_CHECK_BUSY_IOERR
        tErrno = errno;
        rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
        if( IS_LOCK_ERROR(rc) ){
          pFile->lastErrno = tErrno;
        }
#else
        rc = SQLITE_IOERR_UNLOCK;
	    pFile->lastErrno = errno;
#endif
        pInode->eFileLock = NO_LOCK;
        pFile->eFileLock = NO_LOCK;
      }
    }

    /* Decrement the count of locks against this same file.  When the
    ** count reaches zero, close any other file descriptors whose close
1743
1744
1745
1746
1747
1748
1749




















1750
1751
1752
1753
1754
1755
1756
1757

1758
1759
1760
1761
1762
1763
1764
**
** It is *not* necessary to hold the mutex when this routine is called,
** even on VxWorks.  A mutex will be acquired on VxWorks by the
** vxworksReleaseFileId() routine.
*/
static int closeUnixFile(sqlite3_file *id){
  unixFile *pFile = (unixFile*)id;




















  if( pFile->dirfd>=0 ){
    robust_close(pFile, pFile->dirfd, __LINE__);
    pFile->dirfd=-1;
  }
  if( pFile->h>=0 ){
    robust_close(pFile, pFile->h, __LINE__);
    pFile->h = -1;
  }

#if OS_VXWORKS
  if( pFile->pId ){
    if( pFile->isDelete ){
      unlink(pFile->pId->zCanonicalName);
    }
    vxworksReleaseFileId(pFile->pId);
    pFile->pId = 0;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








>







2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
**
** It is *not* necessary to hold the mutex when this routine is called,
** even on VxWorks.  A mutex will be acquired on VxWorks by the
** vxworksReleaseFileId() routine.
*/
static int closeUnixFile(sqlite3_file *id){
  unixFile *pFile = (unixFile*)id;
#if OSCLOSE_CHECK_CLOSE_IOERR
  if( pFile->dirfd>=0 ){
    int err = close(pFile->dirfd);
    if( err ){
      pFile->lastErrno = errno;
      return SQLITE_IOERR_DIR_CLOSE;
    }else{
      pFile->dirfd=-1;
    }
  }
  if( pFile->h>=0 ){
    int err = close(pFile->h);
    if( err ){
      pFile->lastErrno = errno;
      return SQLITE_IOERR_CLOSE;
    }else{
      pFile->h=-1;
    }
  }
#else
  if( pFile->dirfd>=0 ){
    robust_close(pFile, pFile->dirfd, __LINE__);
    pFile->dirfd=-1;
  }
  if( pFile->h>=0 ){
    robust_close(pFile, pFile->h, __LINE__);
    pFile->h = -1;
  }
#endif
#if OS_VXWORKS
  if( pFile->pId ){
    if( pFile->isDelete ){
      unlink(pFile->pId->zCanonicalName);
    }
    vxworksReleaseFileId(pFile->pId);
    pFile->pId = 0;
1963
1964
1965
1966
1967
1968
1969






1970

1971
1972
1973
1974
1975
1976
1977
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( IS_LOCK_ERROR(rc) ){
        pFile->lastErrno = tErrno;
      }
    }
    return rc;
  } 






  robust_close(pFile, fd, __LINE__);

  
  /* got it, set the type and return ok */
  pFile->eFileLock = eFileLock;
  return rc;
}

/*







>
>
>
>
>
>

>







2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( IS_LOCK_ERROR(rc) ){
        pFile->lastErrno = tErrno;
      }
    }
    return rc;
  } 
#if OSCLOSE_CHECK_CLOSE_IOERR
  if( close(fd) ){
    pFile->lastErrno = errno;
    rc = SQLITE_IOERR_CLOSE;
  }
#else
  robust_close(pFile, fd, __LINE__);
#endif
  
  /* got it, set the type and return ok */
  pFile->eFileLock = eFileLock;
  return rc;
}

/*
2007
2008
2009
2010
2011
2012
2013



2014

2015
2016
2017
2018
2019
2020
2021
  
  /* To fully unlock the database, delete the lock file */
  assert( eFileLock==NO_LOCK );
  if( unlink(zLockFile) ){
    int rc = 0;
    int tErrno = errno;
    if( ENOENT != tErrno ){



      rc = SQLITE_IOERR_UNLOCK;

    }
    if( IS_LOCK_ERROR(rc) ){
      pFile->lastErrno = tErrno;
    }
    return rc; 
  }
  pFile->eFileLock = NO_LOCK;







>
>
>

>







2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
  
  /* To fully unlock the database, delete the lock file */
  assert( eFileLock==NO_LOCK );
  if( unlink(zLockFile) ){
    int rc = 0;
    int tErrno = errno;
    if( ENOENT != tErrno ){
#if OSLOCKING_CHECK_BUSY_IOERR
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
      rc = SQLITE_IOERR_UNLOCK;
#endif
    }
    if( IS_LOCK_ERROR(rc) ){
      pFile->lastErrno = tErrno;
    }
    return rc; 
  }
  pFile->eFileLock = NO_LOCK;
2095
2096
2097
2098
2099
2100
2101



2102

2103
2104
2105
2106
2107
2108
2109
    int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
    if( !lrc ){
      /* got the lock, unlock it */
      lrc = robust_flock(pFile->h, LOCK_UN);
      if ( lrc ) {
        int tErrno = errno;
        /* unlock failed with an error */



        lrc = SQLITE_IOERR_UNLOCK; 

        if( IS_LOCK_ERROR(lrc) ){
          pFile->lastErrno = tErrno;
          rc = lrc;
        }
      }
    } else {
      int tErrno = errno;







>
>
>

>







2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
    int lrc = robust_flock(pFile->h, LOCK_EX | LOCK_NB);
    if( !lrc ){
      /* got the lock, unlock it */
      lrc = robust_flock(pFile->h, LOCK_UN);
      if ( lrc ) {
        int tErrno = errno;
        /* unlock failed with an error */
#if OSLOCKING_CHECK_BUSY_IOERR
        lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else 
        lrc = SQLITE_IOERR_UNLOCK; 
#endif
        if( IS_LOCK_ERROR(lrc) ){
          pFile->lastErrno = tErrno;
          rc = lrc;
        }
      }
    } else {
      int tErrno = errno;
3313
3314
3315
3316
3317
3318
3319
3320








3321
3322

3323
3324
3325
3326
3327
3328
3329
       ** A failed directory sync is not a big deal.  So it seems
       ** better to ignore the error.  Ticket #1657
       */
       /* pFile->lastErrno = errno; */
       /* return SQLITE_IOERR; */
    }
#endif
    /* Only need to sync once, so close the  directory when we are done */








    robust_close(pFile, pFile->dirfd, __LINE__);
    pFile->dirfd = -1;

  }
  return rc;
}

/*
** Truncate an open file to a specified size
*/







|
>
>
>
>
>
>
>
>


>







3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
       ** A failed directory sync is not a big deal.  So it seems
       ** better to ignore the error.  Ticket #1657
       */
       /* pFile->lastErrno = errno; */
       /* return SQLITE_IOERR; */
    }
#endif
  /* Only need to sync once, so close the  directory when we are done */
#if OSCLOSE_CHECK_CLOSE_IOERR
    if( close(pFile->dirfd)==0 ){
      pFile->dirfd = -1;
    }else{
      pFile->lastErrno = errno;
      rc = SQLITE_IOERR_DIR_CLOSE;
    }
#else
    robust_close(pFile, pFile->dirfd, __LINE__);
    pFile->dirfd = -1;
#endif
  }
  return rc;
}

/*
** Truncate an open file to a specified size
*/
3454
3455
3456
3457
3458
3459
3460

3461
3462
3463
3464
3465
3466
3467
}

#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
#include "sqlite3_private.h"
#include <copyfile.h>
static int getDbPathForUnixFile(unixFile *pFile, char *dbPath);
#endif


/*
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {







>







3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
}

#if (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__)
#include "sqlite3_private.h"
#include <copyfile.h>
static int getDbPathForUnixFile(unixFile *pFile, char *dbPath);
#endif
static int isProxyLockingMode(unixFile *);

/*
** Information and control of an open file handle.
*/
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
  switch( op ){
    case SQLITE_FCNTL_LOCKSTATE: {
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509




3510
3511
3512

3513

3514
3515

3516
3517

3518

3519
3520
3521

3522







3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566











3567
3568
3569
3570
3571

3572




3573

3574




3575
3576
3577



3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592

3593

3594
3595

3596

3597
3598
3599
3600
3601


3602
3603

3604
3605
3606
3607
3608
3609
3610


3611


3612
3613
3614
3615
3616
3617
3618



3619
3620
3621
3622
3623

3624

3625






3626













3627
3628
3629
3630
3631
3632
3633
3634

3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647

3648
3649

3650

3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661


3662

3663
3664
3665
3666
3667

3668
3669
3670
3671
3672



3673
3674
3675
3676
3677





3678

3679
3680







3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695

3696
3697
3698
3699
3700
3701

3702
3703
3704


3705

3706

3707

3708
3709
3710
3711
3712
3713
3714
    case SQLITE_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 trc = SQLITE_OK;
      int eFileLock = pFile->eFileLock;
      int rc = SQLITE_OK;
      char jPath[MAXPATHLEN+9];
      size_t jLen;
      
      if( eFileLock<SQLITE_LOCK_SHARED ){
        rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED);




      }
      if( !rc && eFileLock<SQLITE_LOCK_EXCLUSIVE ){
        rc = pFile->pMethod->xLock(id, SQLITE_LOCK_EXCLUSIVE);

      }

      if( rc ){
        if( pFile->eFileLock > eFileLock ){

          pFile->pMethod->xUnlock(id, eFileLock);
        }

        return rc;

      }
      rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
      if( !rc && (SQLITE_OK==getDbPathForUnixFile(pFile, jPath)) ){

        jLen = strlcat(jPath, "-journal", MAXPATHLEN+9);







        if( jLen < MAXPATHLEN+9 ){
          int jfd = open(jPath, O_TRUNC);
          if( (jfd == -1) ){
            if ( errno!=ENOENT ){
              perror(jPath);
            }
          } else {
            fsync(jfd);
            close(jfd);
          }
        }
      }else{
        trc=rc;
      }
      if( !trc ){
        trc = pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
      }
      if( pFile->eFileLock > eFileLock ){
        int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_SHARED);
        if (!rc) rc = unlockRC;
      }
      if( pFile->eFileLock > eFileLock ){
        int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_NONE);
        if (!rc) rc = unlockRC;
      }
      if( trc ){
        return trc;
      }
      return rc;
    }
      
    case SQLITE_REPLACE_DATABASE: {
      unixFile *pFile = (unixFile*)id;
      int trc = SQLITE_OK;
      int eFileLock = pFile->eFileLock;
      int rc = SQLITE_OK;
      char jPath[MAXPATHLEN+9];
      size_t jLen;
      sqlite3 *srcdb = (sqlite3 *)pArg;
      Btree *pSrcBtree = NULL;
      int eSrcFileLock = SQLITE_LOCK_NONE;
      int srcLockRC = -1;
      sqlite3_file *src_file = NULL;
      unixFile *pSrcFile = NULL;











      
      if( !sqlite3SafetyCheckOk(srcdb) ){
        return SQLITE_MISUSE;
      }
      if( eFileLock<SQLITE_LOCK_SHARED ){

        rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED);




      }

      if( !rc && eFileLock<SQLITE_LOCK_EXCLUSIVE ){




        rc = pFile->pMethod->xLock(id, SQLITE_LOCK_EXCLUSIVE);
      }
      if( !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 ){

            pSrcFile = (unixFile *)src_file;

            eSrcFileLock = pSrcFile->eFileLock;
            if( eSrcFileLock<SQLITE_LOCK_SHARED ){

              rc = pSrcFile->pMethod->xLock(src_file, SQLITE_LOCK_SHARED);

              srcLockRC = rc; /* SQLITE_OK means we need to unlock later */
            } else if( eSrcFileLock==SQLITE_LOCK_EXCLUSIVE ){
              /* if the src database has an exclusive lock, verify that the
               ** it doesn't have a journal file with open transactions 
               */


              if( getDbPathForUnixFile(pSrcFile, jPath) ){
                rc = SQLITE_INTERNAL;

              }else{
                jLen = strlcat(jPath, "-journal", MAXPATHLEN+9);
                if( jLen < MAXPATHLEN+9 ){
                  int jfd = open(jPath, O_RDONLY);
                  if( jfd==-1 ){
                    if( errno!=ENOENT ){
                      pFile->lastErrno = errno;


                      rc = SQLITE_IOERR;


                    }
                  }else{
                    /* if the journal exists ensure there's no pending 
                     ** transaction by checking the journal header */
                    char magic[8];
                    ssize_t rlen = pread(jfd, magic, 8, 0);
                    if( rlen<0 ){



                      pFile->lastErrno = errno;
                      rc = SQLITE_IOERR;
                    }else if( rlen==8 ){
                      char test[8] = {'\0','\0','\0','\0','\0','\0','\0','\0'};
                      if( memcmp(magic,test,8) ){

                        rc = SQLITE_LOCKED;

                      }






                    }else if( rlen!=0 ){













                      rc = SQLITE_INTERNAL;
                    }
                    close(jfd);
                  }
                }
              }
            }
          }else{

            rc = SQLITE_MISUSE;
          }
          if( rc ){
            if( srcLockRC==SQLITE_OK ){
              pSrcFile->pMethod->xUnlock(src_file, eSrcFileLock);
            }
            sqlite3BtreeLeave(pSrcBtree);
          }
        }
        if( pSrcFile==NULL || (pSrcFile->h<0) ){
          rc = SQLITE_INTERNAL;
          sqlite3_mutex_leave(srcdb->mutex);
        }

      }
      if( rc ){

        /* unroll state changes and return error code */

        if( pFile->eFileLock > eFileLock ){
          pFile->pMethod->xUnlock(id, eFileLock);
        }
        return rc;
      }else{
        /* both databases are locked appropriately, copy file data
         ** and then unroll the locks we added. 
         */
        copyfile_state_t s;
        
        s = copyfile_state_alloc();


        if( fcopyfile(pSrcFile->h, pFile->h, s, COPYFILE_ALL) ){

          switch(errno) {
            case ENOMEM:
              rc = SQLITE_NOMEM;
              break;
            default:

              rc = SQLITE_INTERNAL;
          }
        }
        copyfile_state_free(s);
        if( srcLockRC==SQLITE_OK ){



          pSrcFile->pMethod->xUnlock(src_file, eSrcFileLock);
        }
        sqlite3BtreeLeave(pSrcBtree);
        sqlite3_mutex_leave(srcdb->mutex);
      }





      

      if( !rc && (SQLITE_OK==getDbPathForUnixFile(pFile, jPath)) ){
        jLen = strlcat(jPath, "-journal", MAXPATHLEN+9);







        if( jLen < MAXPATHLEN+9 ){
          int jfd = open(jPath, O_TRUNC);
          if( (jfd == -1) ){
            if ( errno!=ENOENT ){
              perror(jPath);
            }
          } else {
            fsync(jfd);
            close(jfd);
          }
        }
      }else{
        trc=rc;
      }
      if( !trc ){

        trc = pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);
      }
      if( pFile->eFileLock > eFileLock ){
        int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_SHARED);
        if (!rc) rc = unlockRC;
      }

      if( pFile->eFileLock > eFileLock ){
        int unlockRC = pFile->pMethod->xUnlock(id, SQLITE_LOCK_NONE);
        if (!rc) rc = unlockRC;


      }

      if( trc ){

        return trc;

      }
      return rc;
    }
#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;  /* A no-op */
    }







|
|
|
|
|
|
|
|
>
>
>
>

<
<
>
|
>

|
>
|

>
|
>


|
>
|
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
<
<
|
<
<
|
<
|
<

|
<
|
|
<
|






<
<
<
<
<


<
<


>
>
>
>
>
>
>
>
>
>
>
|



|
>
|
>
>
>
>

>
|
>
>
>
>
|
|
|
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
>
|
|
>
|
>
|
|
<
<
<
>
>
|
|
>
|
<
<
|
|
<
<
>
>
|
>
>
|
<
<
<
<
<
<
>
>
>
|
|
<
<
<
>
|
>
|
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
|
<
<
<
<
|
>
|
|
<
<
<
<
<
<
|
|
|
<

>

|
>
|
>
|
|
|
<
<
<
<
<
<
|

>
>

>
|




>
|



|
>
>
>
|

<
<

>
>
>
>
>
|
>
|
|
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
<
<
|
<
>
|

<
<
<
|
>
|
<
<
>
>

>
|
>
|
>







3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900


3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934


3935


3936

3937

3938
3939

3940
3941

3942
3943
3944
3945
3946
3947
3948





3949
3950


3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012



4013
4014
4015
4016
4017
4018


4019
4020


4021
4022
4023
4024
4025
4026






4027
4028
4029
4030
4031



4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056

4057




4058
4059
4060
4061






4062
4063
4064

4065
4066
4067
4068
4069
4070
4071
4072
4073
4074






4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096


4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124


4125

4126
4127
4128



4129
4130
4131


4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
    case SQLITE_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_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) ){
        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);
      }
      return rc;
    }
#endif /* (SQLITE_ENABLE_APPLE_SPI>0) && defined(__APPLE__) */
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;  /* A no-op */
    }
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
      p->h = -1;
    }
    p->pInode->pShmNode = 0;
    sqlite3_free(p);
  }
}

static int isProxyLockingMode(unixFile *);
static const char *proxySharedMemoryBasePath(unixFile *);

/*
** Open a shared-memory area associated with open database file pDbFd.  
** This particular implementation uses mmapped files.
**
** The file used to implement shared-memory is in the same directory







<







4352
4353
4354
4355
4356
4357
4358

4359
4360
4361
4362
4363
4364
4365
      p->h = -1;
    }
    p->pInode->pShmNode = 0;
    sqlite3_free(p);
  }
}


static const char *proxySharedMemoryBasePath(unixFile *);

/*
** Open a shared-memory area associated with open database file pDbFd.  
** This particular implementation uses mmapped files.
**
** The file used to implement shared-memory is in the same directory
4058
4059
4060
4061
4062
4063
4064








4065
4066
4067
4068
4069
4070
4071
      /* 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( rc==SQLITE_OK ){
        rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
      }
      if( rc ) goto shm_open_err;
    }







>
>
>
>
>
>
>
>







4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
      /* 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);
        }else{
          /* If running as root set the uid/gid of the shm file to match the database */
          uid_t euid = geteuid();
          if( euid==0 && (euid!=sStat.st_uid || getegid()!=sStat.st_gid) ){
            if( fchown(pShmNode->h, sStat.st_uid, sStat.st_gid) ){
              rc = SQLITE_IOERR_SHMOPEN;
            }
          }
        }
      }
      if( rc==SQLITE_OK ){
        rc = unixShmSystemLock(pShmNode, F_RDLCK, UNIX_SHM_DMS, 1);
      }
      if( rc ) goto shm_open_err;
    }
5077
5078
5079
5080
5081
5082
5083
5084


5085
5086
5087
5088
5089
5090
5091
** original filename is unavailable.  But 8_3_NAMES is only used for
** FAT filesystems and permissions do not matter there, so just use
** the default permissions.
*/
static int findCreateFileMode(
  const char *zPath,              /* Path of file (possibly) being created */
  int flags,                      /* Flags passed as 4th argument to xOpen() */
  mode_t *pMode                   /* OUT: Permissions to open file with */


){
  int rc = SQLITE_OK;             /* Return Code */
  *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;
  if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
    char zDb[MAX_PATHNAME+1];     /* Database file path */
    int nDb;                      /* Number of valid bytes in zDb */
    struct stat sStat;            /* Output of stat() on database file */







|
>
>







5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
** original filename is unavailable.  But 8_3_NAMES is only used for
** FAT filesystems and permissions do not matter there, so just use
** the default permissions.
*/
static int findCreateFileMode(
  const char *zPath,              /* Path of file (possibly) being created */
  int flags,                      /* Flags passed as 4th argument to xOpen() */
  mode_t *pMode,                  /* OUT: Permissions to open file with */
  uid_t *pUid,                    /* OUT: uid to set on the file */
  gid_t *pGid                     /* OUT: gid to set on the file */
){
  int rc = SQLITE_OK;             /* Return Code */
  *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;
  if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
    char zDb[MAX_PATHNAME+1];     /* Database file path */
    int nDb;                      /* Number of valid bytes in zDb */
    struct stat sStat;            /* Output of stat() on database file */
5106
5107
5108
5109
5110
5111
5112


5113
5114
5115
5116
5117
5118
5119
    while( nDb>0 && zPath[nDb]!='-' ) nDb--;
    if( nDb==0 ) return SQLITE_OK;
    memcpy(zDb, zPath, nDb);
    zDb[nDb] = '\0';

    if( 0==stat(zDb, &sStat) ){
      *pMode = sStat.st_mode & 0777;


    }else{
      rc = SQLITE_IOERR_FSTAT;
    }
  }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
    *pMode = 0600;
  }
  return rc;







>
>







5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
    while( nDb>0 && zPath[nDb]!='-' ) nDb--;
    if( nDb==0 ) return SQLITE_OK;
    memcpy(zDb, zPath, nDb);
    zDb[nDb] = '\0';

    if( 0==stat(zDb, &sStat) ){
      *pMode = sStat.st_mode & 0777;
      *pUid = sStat.st_uid;
      *pGid = sStat.st_gid;
    }else{
      rc = SQLITE_IOERR_FSTAT;
    }
  }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
    *pMode = 0600;
  }
  return rc;
5148
5149
5150
5151
5152
5153
5154



5155

5156
5157
5158
5159
5160
5161
5162
  int flags,                   /* Input flags to control the opening */
  int *pOutFlags               /* Output flags returned to SQLite core */
){
  unixFile *p = (unixFile *)pFile;
  int fd = -1;                   /* File descriptor returned by open() */
  int dirfd = -1;                /* Directory file descriptor */
  int openFlags = 0;             /* Flags to pass to open() */



  int eType = flags&0xFFFFFF00;  /* Type of file to open */

  int noLock;                    /* True to omit locking primitives */
  int rc = SQLITE_OK;            /* Function Return Code */

  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
  int isCreate     = (flags & SQLITE_OPEN_CREATE);
  int isReadonly   = (flags & SQLITE_OPEN_READONLY);







>
>
>

>







5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
  int flags,                   /* Input flags to control the opening */
  int *pOutFlags               /* Output flags returned to SQLite core */
){
  unixFile *p = (unixFile *)pFile;
  int fd = -1;                   /* File descriptor returned by open() */
  int dirfd = -1;                /* Directory file descriptor */
  int openFlags = 0;             /* Flags to pass to open() */
#if SQLITE_ENABLE_DATA_PROTECTION
  int eType = flags&0xFF0FFF00;  /* Type of file to open */
#else
  int eType = flags&0xFFFFFF00;  /* Type of file to open */
#endif
  int noLock;                    /* True to omit locking primitives */
  int rc = SQLITE_OK;            /* Function Return Code */

  int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
  int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
  int isCreate     = (flags & SQLITE_OPEN_CREATE);
  int isReadonly   = (flags & SQLITE_OPEN_READONLY);
5237
5238
5239
5240
5241
5242
5243




5244
5245


5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265










5266
5267
5268
5269
5270
5271
5272
  ** 'conch file' locking functions later on.  */
  if( isReadonly )  openFlags |= O_RDONLY;
  if( isReadWrite ) openFlags |= O_RDWR;
  if( isCreate )    openFlags |= O_CREAT;
  if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
  openFlags |= (O_LARGEFILE|O_BINARY);





  if( fd<0 ){
    mode_t openMode;              /* Permissions to create file with */


    rc = findCreateFileMode(zName, flags, &openMode);
    if( rc!=SQLITE_OK ){
      assert( !p->pUnused );
      assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
      return rc;
    }
    fd = robust_open(zName, openFlags, openMode);
    OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
    if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
      /* Failed to open the file for read/write access. Try read-only. */
      flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
      openFlags &= ~(O_RDWR|O_CREAT);
      flags |= SQLITE_OPEN_READONLY;
      openFlags |= O_RDONLY;
      isReadonly = 1;
      fd = robust_open(zName, openFlags, openMode);
    }
    if( fd<0 ){
      rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
      goto open_finished;










    }
  }
  assert( fd>=0 );
  if( pOutFlags ){
    *pOutFlags = flags;
  }








>
>
>
>


>
>
|



















>
>
>
>
>
>
>
>
>
>







5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
  ** 'conch file' locking functions later on.  */
  if( isReadonly )  openFlags |= O_RDONLY;
  if( isReadWrite ) openFlags |= O_RDWR;
  if( isCreate )    openFlags |= O_CREAT;
  if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
  openFlags |= (O_LARGEFILE|O_BINARY);

#if SQLITE_ENABLE_DATA_PROTECTION
  p->protFlags = (flags & SQLITE_OPEN_FILEPROTECTION_MASK);
#endif
    
  if( fd<0 ){
    mode_t openMode;              /* Permissions to create file with */
    uid_t uid;
    gid_t gid;
    rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
    if( rc!=SQLITE_OK ){
      assert( !p->pUnused );
      assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
      return rc;
    }
    fd = robust_open(zName, openFlags, openMode);
    OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
    if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){
      /* Failed to open the file for read/write access. Try read-only. */
      flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
      openFlags &= ~(O_RDWR|O_CREAT);
      flags |= SQLITE_OPEN_READONLY;
      openFlags |= O_RDONLY;
      isReadonly = 1;
      fd = robust_open(zName, openFlags, openMode);
    }
    if( fd<0 ){
      rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
      goto open_finished;
    }
    /* if we're opening the wal or journal and running as root, set the journal uid/gid */
    if( !isReadonly && (flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL)) ){
      uid_t euid = geteuid();
      if( euid==0 && (euid!=uid || getegid()!=gid) ){
        if( fchown(fd, uid, gid) ){
          rc = SQLITE_CANTOPEN_BKPT;
          goto open_finished;
        }
      }
    }
  }
  assert( fd>=0 );
  if( pOutFlags ){
    *pOutFlags = flags;
  }

5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
    int useProxy = 0;

    /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means 
    ** never use proxy, NULL means use proxy for non-local files only.  */
    if( envforce!=NULL ){
      useProxy = atoi(envforce)>0;
    }else{
      struct statfs fsInfo;
      if( statfs(zPath, &fsInfo) == -1 ){
        /* In theory, the close(fd) call is sub-optimal. If the file opened
        ** with fd is a database file, and there are other connections open
        ** on that file that are currently holding advisory locks on it,
        ** then the call to close() will cancel those locks. In practice,
        ** we're assuming that statfs() doesn't fail very often. At least
        ** not while other file descriptors opened by the same process on
        ** the same file are working.  */
        p->lastErrno = errno;
        if( dirfd>=0 ){
          robust_close(p, dirfd, __LINE__);
        }
        robust_close(p, fd, __LINE__);
        rc = SQLITE_IOERR_ACCESS;
        goto open_finished;
      }
      useProxy = !(fsInfo.f_flags&MNT_LOCAL);
    }
    if( useProxy ){
      rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock,
                          isDelete, isReadonly);
      if( rc==SQLITE_OK ){
        /* cache the pMethod in case the transform fails */







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







5796
5797
5798
5799
5800
5801
5802

















5803
5804
5805
5806
5807
5808
5809
    int useProxy = 0;

    /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means 
    ** never use proxy, NULL means use proxy for non-local files only.  */
    if( envforce!=NULL ){
      useProxy = atoi(envforce)>0;
    }else{

















      useProxy = !(fsInfo.f_flags&MNT_LOCAL);
    }
    if( useProxy ){
      rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock,
                          isDelete, isReadonly);
      if( rc==SQLITE_OK ){
        /* cache the pMethod in case the transform fails */
5415
5416
5417
5418
5419
5420
5421





5422

5423
5424
5425
5426
5427
5428
5429
      if( fsync(fd)==-1 )
#else
      if( fsync(fd) )
#endif
      {
        rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
      }





      robust_close(0, fd, __LINE__);

    }
  }
#endif
  return rc;
}

/*







>
>
>
>
>

>







5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
      if( fsync(fd)==-1 )
#else
      if( fsync(fd) )
#endif
      {
        rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath);
      }
#if OSCLOSE_CHECK_CLOSE_IOERR
      if( close(fd)&&!rc ){
        rc = SQLITE_IOERR_DIR_CLOSE;
      }
#else
      robust_close(0, fd, __LINE__);
#endif
    }
  }
#endif
  return rc;
}

/*
5881
5882
5883
5884
5885
5886
5887

5888
5889
5890
5891
5892
5893
5894
struct proxyLockingContext {
  unixFile *conchFile;         /* Open conch file */
  char *conchFilePath;         /* Name of the conch file */
  unixFile *lockProxy;         /* Open proxy lock file */
  char *lockProxyPath;         /* Name of the proxy lock file */
  char *dbPath;                /* Name of the open file */
  int conchHeld;               /* 1 if the conch is held, -1 if lockless */

  void *oldLockingContext;     /* Original lockingcontext to restore on close */
  sqlite3_io_methods const *pOldMethod;     /* Original I/O methods for close */
};

/* 
** The proxy lock file path for the database at dbPath is written into lPath, 
** which must point to valid, writable memory large enough for a maxLen length







>







6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
struct proxyLockingContext {
  unixFile *conchFile;         /* Open conch file */
  char *conchFilePath;         /* Name of the conch file */
  unixFile *lockProxy;         /* Open proxy lock file */
  char *lockProxyPath;         /* Name of the proxy lock file */
  char *dbPath;                /* Name of the open file */
  int conchHeld;               /* 1 if the conch is held, -1 if lockless */
  int nFails;                  /* Number of conch taking failures */
  void *oldLockingContext;     /* Original lockingcontext to restore on close */
  sqlite3_io_methods const *pOldMethod;     /* Original I/O methods for close */
};

/* 
** The proxy lock file path for the database at dbPath is written into lPath, 
** which must point to valid, writable memory large enough for a maxLen length
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103

6104
6105
6106
6107
6108
6109
6110

/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN 
** bytes of writable memory.
*/
static int proxyGetHostID(unsigned char *pHostID, int *pError){
  assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
  memset(pHostID, 0, PROXY_HOSTIDLEN);
#if defined(__MAX_OS_X_VERSION_MIN_REQUIRED)\
               && __MAC_OS_X_VERSION_MIN_REQUIRED<1050
  {
    static const struct timespec timeout = {1, 0}; /* 1 sec timeout */

    if( gethostuuid(pHostID, &timeout) ){
      int err = errno;
      if( pError ){
        *pError = err;
      }
      return SQLITE_IOERR;
    }







|
<

|
>







6546
6547
6548
6549
6550
6551
6552
6553

6554
6555
6556
6557
6558
6559
6560
6561
6562
6563

/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN 
** bytes of writable memory.
*/
static int proxyGetHostID(unsigned char *pHostID, int *pError){
  assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
  memset(pHostID, 0, PROXY_HOSTIDLEN);
#if HAVE_GETHOSTUUID

  {
    struct timespec timeout = {1, 0}; /* 1 sec timeout */
    
    if( gethostuuid(pHostID, &timeout) ){
      int err = errno;
      if( pError ){
        *pError = err;
      }
      return SQLITE_IOERR;
    }
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207

6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240



6241












6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
/* Take the requested lock on the conch file and break a stale lock if the 
** host id matches.
*/
static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
  proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; 
  unixFile *conchFile = pCtx->conchFile;
  int rc = SQLITE_OK;
  int nTries = 0;
  struct timespec conchModTime;
  
  do {
    rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
    nTries ++;
    if( rc==SQLITE_BUSY ){

      /* If the lock failed (busy):
       * 1st try: get the mod time of the conch, wait 0.5s and try again. 
       * 2nd try: fail if the mod time changed or host id is different, wait 
       *           10 sec and try again
       * 3rd try: break the lock unless the mod time has changed.
       */
      struct stat buf;
      if( osFstat(conchFile->h, &buf) ){
        pFile->lastErrno = errno;
        return SQLITE_IOERR_LOCK;
      }
      
      if( nTries==1 ){
        conchModTime = buf.st_mtimespec;
        usleep(500000); /* wait 0.5 sec and try the lock again*/
        continue;  
      }

      assert( nTries>1 );
      if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec || 
         conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
        return SQLITE_BUSY;
      }
      
      if( nTries==2 ){  
        char tBuf[PROXY_MAXCONCHLEN];
        int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
        if( len<0 ){
          pFile->lastErrno = errno;
          return SQLITE_IOERR_LOCK;
        }
        if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
          /* don't break the lock if the host id doesn't match */



          if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){












            return SQLITE_BUSY;
          }
        }else{
          /* don't break the lock on short read or a version mismatch */
          return SQLITE_BUSY;
        }
        usleep(10000000); /* wait 10 sec and try the lock again */
        continue; 
      }
      
      assert( nTries==3 );
      if( 0==proxyBreakConchLock(pFile, myHostID) ){
        rc = SQLITE_OK;
        if( lockType==EXCLUSIVE_LOCK ){
          rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);          
        }
        if( !rc ){
          rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
        }
      }
    }
  } while( rc==SQLITE_BUSY && nTries<3 );
  
  return rc;
}

/* Takes the conch by taking a shared lock and read the contents conch, if 
** lockPath is non-NULL, the host ID and lock file path must match.  A NULL 
** lockPath means that the lockPath in the conch file will be used if the 







<




<

>












|





|





|







|
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>










|
|









|







6647
6648
6649
6650
6651
6652
6653

6654
6655
6656
6657

6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
6670
6671
6672
6673
6674
6675
6676
6677
6678
6679
6680
6681
6682
6683
6684
6685
6686
6687
6688
6689
6690
6691
6692
6693
6694
6695
6696
6697
6698
6699
6700
6701
6702
6703
6704
6705
6706
6707
6708
6709
6710
6711
6712
6713
6714
6715
6716
6717
6718
6719
6720
6721
6722
6723
6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
/* Take the requested lock on the conch file and break a stale lock if the 
** host id matches.
*/
static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
  proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext; 
  unixFile *conchFile = pCtx->conchFile;
  int rc = SQLITE_OK;

  struct timespec conchModTime;
  
  do {
    rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);

    if( rc==SQLITE_BUSY ){
      pCtx->nFails ++;
      /* If the lock failed (busy):
       * 1st try: get the mod time of the conch, wait 0.5s and try again. 
       * 2nd try: fail if the mod time changed or host id is different, wait 
       *           10 sec and try again
       * 3rd try: break the lock unless the mod time has changed.
       */
      struct stat buf;
      if( osFstat(conchFile->h, &buf) ){
        pFile->lastErrno = errno;
        return SQLITE_IOERR_LOCK;
      }
      
      if( pCtx->nFails==1 ){
        conchModTime = buf.st_mtimespec;
        usleep(500000); /* wait 0.5 sec and try the lock again*/
        continue;  
      }

      assert( pCtx->nFails>1 );
      if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec || 
         conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
        return SQLITE_BUSY;
      }
      
      if( pCtx->nFails==2 ){  
        char tBuf[PROXY_MAXCONCHLEN];
        int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
        if( len<0 ){
          pFile->lastErrno = errno;
          return SQLITE_IOERR_LOCK;
        }
        if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){
          /* don't break the lock if the host id doesn't match, but do log
           * an error to console so users can diagnose stale NFS locks more 
           * easily 
           */
          if( 0!=memcmp(&tBuf[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN) ){
            uuid_t conchUUID;
            uuid_string_t conchUUIDString;
            uuid_string_t myUUIDString;
            assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
            memcpy(conchUUID, &tBuf[PROXY_HEADERLEN], PROXY_HOSTIDLEN);
            uuid_unparse(conchUUID, conchUUIDString);
            uuid_unparse(myHostID, myUUIDString);
            fprintf(stderr, "ERROR: sqlite database is locked because it is in use "
                    "by another host that holds a host-exclusive lock on %s; "
                    "this host (UUID %s) cannot override the host-exclusive lock "
                    "until the other host (UUID %s) releases its locks on %s\n", 
                    pFile->zPath, myUUIDString, conchUUIDString, conchFile->zPath);
            return SQLITE_BUSY;
          }
        }else{
          /* don't break the lock on short read or a version mismatch */
          return SQLITE_BUSY;
        }
        usleep(10000000); /* wait 10 sec and try the lock again */
        continue; 
      }
      
      assert( pCtx->nFails>=3 );
      if( (pCtx->nFails==3)&&(0==proxyBreakConchLock(pFile, myHostID)) ){
        rc = SQLITE_OK;
        if( lockType==EXCLUSIVE_LOCK ){
          rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, SHARED_LOCK);          
        }
        if( !rc ){
          rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
        }
      }
    }
  } while( rc==SQLITE_BUSY && pCtx->nFails<3 );
  
  return rc;
}

/* Takes the conch by taking a shared lock and read the contents conch, if 
** lockPath is non-NULL, the host ID and lock file path must match.  A NULL 
** lockPath means that the lockPath in the conch file will be used if the 
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
          /* We are trying for an exclusive lock but another thread in this
           ** same process is still holding a shared lock. */
          rc = SQLITE_BUSY;
        } else {          
          rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
        }
      }else{
        rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, EXCLUSIVE_LOCK);
      }
      if( rc==SQLITE_OK ){
        char writeBuffer[PROXY_MAXCONCHLEN];
        int writeSize = 0;
        
        writeBuffer[0] = (char)PROXY_CONCHVERSION;
        memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN);







|







6842
6843
6844
6845
6846
6847
6848
6849
6850
6851
6852
6853
6854
6855
6856
          /* We are trying for an exclusive lock but another thread in this
           ** same process is still holding a shared lock. */
          rc = SQLITE_BUSY;
        } else {          
          rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
        }
      }else{
        rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
      }
      if( rc==SQLITE_OK ){
        char writeBuffer[PROXY_MAXCONCHLEN];
        int writeSize = 0;
        
        writeBuffer[0] = (char)PROXY_CONCHVERSION;
        memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN);
6429
6430
6431
6432
6433
6434
6435






6436

6437
6438
6439
6440
6441
6442
6443
      }
      conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
      
    end_takeconch:
      OSTRACE(("TRANSPROXY: CLOSE  %d\n", pFile->h));
      if( rc==SQLITE_OK && pFile->openFlags ){
        if( pFile->h>=0 ){






          robust_close(pFile, pFile->h, __LINE__);

        }
        pFile->h = -1;
        int fd = robust_open(pCtx->dbPath, pFile->openFlags,
                      SQLITE_DEFAULT_FILE_PERMISSIONS);
        OSTRACE(("TRANSPROXY: OPEN  %d\n", fd));
        if( fd>=0 ){
          pFile->h = fd;







>
>
>
>
>
>

>







6896
6897
6898
6899
6900
6901
6902
6903
6904
6905
6906
6907
6908
6909
6910
6911
6912
6913
6914
6915
6916
6917
      }
      conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
      
    end_takeconch:
      OSTRACE(("TRANSPROXY: CLOSE  %d\n", pFile->h));
      if( rc==SQLITE_OK && pFile->openFlags ){
        if( pFile->h>=0 ){
#if defined(STRICT_CLOSE_ERROR) && OSCLOSE_CHECK_CLOSE_IOERR
          if( close(pFile->h) ){
            pFile->lastErrno = errno;
            return SQLITE_IOERR_CLOSE;
          }
#else
          robust_close(pFile, pFile->h, __LINE__);
#endif
        }
        pFile->h = -1;
        int fd = robust_open(pCtx->dbPath, pFile->openFlags,
                      SQLITE_DEFAULT_FILE_PERMISSIONS);
        OSTRACE(("TRANSPROXY: OPEN  %d\n", fd));
        if( fd>=0 ){
          pFile->h = fd;
Changes to src/pager.c.
2373
2374
2375
2376
2377
2378
2379




2380
2381
2382
2383
2384
2385
2386
2387
  ** If successful, open the master journal file for reading.
  */
  pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
  pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
  if( !pMaster ){
    rc = SQLITE_NOMEM;
  }else{




    const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
    rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
  }
  if( rc!=SQLITE_OK ) goto delmaster_out;

  /* Load the entire master journal file into space obtained from
  ** sqlite3_malloc() and pointed to by zMasterJournal.   Also obtain
  ** sufficient space (in zMasterPtr) to hold the names of master







>
>
>
>
|







2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
  ** If successful, open the master journal file for reading.
  */
  pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
  pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
  if( !pMaster ){
    rc = SQLITE_NOMEM;
  }else{
    const int flags = 
#if SQLITE_ENABLE_DATA_PROTECTION
      (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
#endif
      (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
    rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
  }
  if( rc!=SQLITE_OK ) goto delmaster_out;

  /* Load the entire master journal file into space obtained from
  ** sqlite3_malloc() and pointed to by zMasterJournal.   Also obtain
  ** sufficient space (in zMasterPtr) to hold the names of master
2409
2410
2411
2412
2413
2414
2415




2416
2417
2418
2419
2420
2421
2422
2423
    }
    if( exists ){
      /* One of the journals pointed to by the master journal exists.
      ** Open it and check if it points at the master journal. If
      ** so, return without deleting the master journal file.
      */
      int c;




      int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
      rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
      if( rc!=SQLITE_OK ){
        goto delmaster_out;
      }

      rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
      sqlite3OsClose(pJournal);







>
>
>
>
|







2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
    }
    if( exists ){
      /* One of the journals pointed to by the master journal exists.
      ** Open it and check if it points at the master journal. If
      ** so, return without deleting the master journal file.
      */
      int c;
      int flags = 
#if SQLITE_ENABLE_DATA_PROTECTION
        (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
#endif
        (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
      rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
      if( rc!=SQLITE_OK ){
        goto delmaster_out;
      }

      rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
      sqlite3OsClose(pJournal);
3394
3395
3396
3397
3398
3399
3400




3401
3402
3403
3404
3405
3406
3407
3408
){
  int rc;               /* Return code */

#ifdef SQLITE_TEST
  sqlite3_opentemp_count++;  /* Used for testing and analysis only */
#endif





  vfsFlags |=  SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
            SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
  rc = sqlite3OsOpen(pPager->pVfs, 0, pFile, vfsFlags, 0);
  assert( rc!=SQLITE_OK || isOpen(pFile) );
  return rc;
}

/*







>
>
>
>
|







3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
){
  int rc;               /* Return code */

#ifdef SQLITE_TEST
  sqlite3_opentemp_count++;  /* Used for testing and analysis only */
#endif

  vfsFlags |=  
#if SQLITE_ENABLE_DATA_PROTECTION
            (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
#endif
            SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
            SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
  rc = sqlite3OsOpen(pPager->pVfs, 0, pFile, vfsFlags, 0);
  assert( rc!=SQLITE_OK || isOpen(pFile) );
  return rc;
}

/*
4523
4524
4525
4526
4527
4528
4529



4530

4531
4532
4533
4534
4535
4536
4537
  pPager->changeCountDone = pPager->tempFile;
  pPager->memDb = (u8)memDb;
  pPager->readOnly = (u8)readOnly;
  assert( useJournal || pPager->tempFile );
  pPager->noSync = pPager->tempFile;
  pPager->fullSync = pPager->noSync ?0:1;
  pPager->syncFlags = pPager->noSync ? 0 : SQLITE_SYNC_NORMAL;



  pPager->ckptSyncFlags = pPager->syncFlags;

  /* pPager->pFirst = 0; */
  /* pPager->pFirstSynced = 0; */
  /* pPager->pLast = 0; */
  pPager->nExtra = (u16)nExtra;
  pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT;
  assert( isOpen(pPager->fd) || tempFile );
  setSectorSize(pPager);







>
>
>

>







4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
  pPager->changeCountDone = pPager->tempFile;
  pPager->memDb = (u8)memDb;
  pPager->readOnly = (u8)readOnly;
  assert( useJournal || pPager->tempFile );
  pPager->noSync = pPager->tempFile;
  pPager->fullSync = pPager->noSync ?0:1;
  pPager->syncFlags = pPager->noSync ? 0 : SQLITE_SYNC_NORMAL;
#if SQLITE_DEFAULT_CKPTFULLFSYNC
  pPager->ckptSyncFlags = pPager->noSync ? 0 : SQLITE_SYNC_FULL;
#else
  pPager->ckptSyncFlags = pPager->syncFlags;
#endif
  /* pPager->pFirst = 0; */
  /* pPager->pFirstSynced = 0; */
  /* pPager->pLast = 0; */
  pPager->nExtra = (u16)nExtra;
  pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT;
  assert( isOpen(pPager->fd) || tempFile );
  setSectorSize(pPager);
4634
4635
4636
4637
4638
4639
4640




4641
4642
4643
4644
4645
4646
4647
4648
          /* The journal file exists and no other connection has a reserved
          ** or greater lock on the database file. Now check that there is
          ** at least one non-zero bytes at the start of the journal file.
          ** If there is, then we consider this journal to be hot. If not, 
          ** it can be ignored.
          */
          if( !jrnlOpen ){




            int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
            rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
          }
          if( rc==SQLITE_OK ){
            u8 first = 0;
            rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
            if( rc==SQLITE_IOERR_SHORT_READ ){
              rc = SQLITE_OK;







>
>
>
>
|







4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
          /* The journal file exists and no other connection has a reserved
          ** or greater lock on the database file. Now check that there is
          ** at least one non-zero bytes at the start of the journal file.
          ** If there is, then we consider this journal to be hot. If not, 
          ** it can be ignored.
          */
          if( !jrnlOpen ){
            int f = 
#if SQLITE_ENABLE_DATA_PROTECTION
              (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
#endif
              SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
            rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
          }
          if( rc==SQLITE_OK ){
            u8 first = 0;
            rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
            if( rc==SQLITE_IOERR_SHORT_READ ){
              rc = SQLITE_OK;
4772
4773
4774
4775
4776
4777
4778




4779
4780
4781
4782
4783
4784
4785
4786
      if( !isOpen(pPager->jfd) ){
        sqlite3_vfs * const pVfs = pPager->pVfs;
        int bExists;              /* True if journal file exists */
        rc = sqlite3OsAccess(
            pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &bExists);
        if( rc==SQLITE_OK && bExists ){
          int fout = 0;




          int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
          assert( !pPager->tempFile );
          rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
          assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
          if( rc==SQLITE_OK && fout&SQLITE_OPEN_READONLY ){
            rc = SQLITE_CANTOPEN_BKPT;
            sqlite3OsClose(pPager->jfd);
          }







>
>
>
>
|







4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
      if( !isOpen(pPager->jfd) ){
        sqlite3_vfs * const pVfs = pPager->pVfs;
        int bExists;              /* True if journal file exists */
        rc = sqlite3OsAccess(
            pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &bExists);
        if( rc==SQLITE_OK && bExists ){
          int fout = 0;
          int f = 
#if SQLITE_ENABLE_DATA_PROTECTION
            (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
#endif
            SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
          assert( !pPager->tempFile );
          rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &fout);
          assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
          if( rc==SQLITE_OK && fout&SQLITE_OPEN_READONLY ){
            rc = SQLITE_CANTOPEN_BKPT;
            sqlite3OsClose(pPager->jfd);
          }
5148
5149
5150
5151
5152
5153
5154



5155
5156
5157
5158
5159
5160
5161
  
    /* Open the journal file if it is not already open. */
    if( !isOpen(pPager->jfd) ){
      if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
        sqlite3MemJournalOpen(pPager->jfd);
      }else{
        const int flags =                   /* VFS flags to open journal file */



          SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
          (pPager->tempFile ? 
            (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
            (SQLITE_OPEN_MAIN_JOURNAL)
          );
  #ifdef SQLITE_ENABLE_ATOMIC_WRITE
        rc = sqlite3JournalOpen(







>
>
>







5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
  
    /* Open the journal file if it is not already open. */
    if( !isOpen(pPager->jfd) ){
      if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
        sqlite3MemJournalOpen(pPager->jfd);
      }else{
        const int flags =                   /* VFS flags to open journal file */
#if SQLITE_ENABLE_DATA_PROTECTION
          (pPager->vfsFlags&SQLITE_OPEN_FILEPROTECTION_MASK)|
#endif
          SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
          (pPager->tempFile ? 
            (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
            (SQLITE_OPEN_MAIN_JOURNAL)
          );
  #ifdef SQLITE_ENABLE_ATOMIC_WRITE
        rc = sqlite3JournalOpen(
6706
6707
6708
6709
6710
6711
6712

6713



6714
6715
6716

6717
6718
6719
6720
6721
6722
6723
    rc = pagerExclusiveLock(pPager);
  }

  /* Open the connection to the log file. If this operation fails, 
  ** (e.g. due to malloc() failure), return an error code.
  */
  if( rc==SQLITE_OK ){

    rc = sqlite3WalOpen(pPager->pVfs, 



        pPager->fd, pPager->zWal, pPager->exclusiveMode,
        pPager->journalSizeLimit, &pPager->pWal
    );

  }

  return rc;
}


/*







>
|
>
>
>
|
|
<
>







6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743
6744
6745
6746

6747
6748
6749
6750
6751
6752
6753
6754
    rc = pagerExclusiveLock(pPager);
  }

  /* Open the connection to the log file. If this operation fails, 
  ** (e.g. due to malloc() failure), return an error code.
  */
  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->pWal);
#else
    rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode,
        pPager->journalSizeLimit, 0, &pPager->pWal);

#endif
  }

  return rc;
}


/*
Changes to src/pragma.c.
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
    assert( pBt!=0 );
    if( zRight ){
      b = sqlite3GetBoolean(zRight);
    }
    if( pId2->n==0 && b>=0 ){
      int ii;
      for(ii=0; ii<db->nDb; ii++){
        sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b);
      }
    }
    b = sqlite3BtreeSecureDelete(pBt, b);
    returnSingleInt(pParse, "secure_delete", &b);
  }else

  /*
  **  PRAGMA [database.]max_page_count
  **  PRAGMA [database.]max_page_count=N
  **







|


|







437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
    assert( pBt!=0 );
    if( zRight ){
      b = sqlite3GetBoolean(zRight);
    }
    if( pId2->n==0 && b>=0 ){
      int ii;
      for(ii=0; ii<db->nDb; ii++){
        sqlite3BtreeSecureDelete(db->aDb[ii].pBt, (int)b);
      }
    }
    b = (int)sqlite3BtreeSecureDelete(pBt, (int)b);
    returnSingleInt(pParse, "secure_delete", &b);
  }else

  /*
  **  PRAGMA [database.]max_page_count
  **  PRAGMA [database.]max_page_count=N
  **
560
561
562
563
564
565
566








567
568
569
570
571
572
573
      }
    }
    if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){
      /* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */
      iDb = 0;
      pId2->n = 1;
    }








    for(ii=db->nDb-1; ii>=0; ii--){
      if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
        sqlite3VdbeUsesBtree(v, ii);
        sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode);
      }
    }
    sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);







>
>
>
>
>
>
>
>







560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
      }
    }
    if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){
      /* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */
      iDb = 0;
      pId2->n = 1;
    }
#ifdef SQLITE_DEFAULT_WAL_SAFETYLEVEL
    if (eMode == PAGER_JOURNALMODE_WAL) {
      /* when entering wal mode, immediately switch the safety_level
       * so that a query to pragma synchronous returns the correct value
       */
      pDb->safety_level = SQLITE_DEFAULT_WAL_SAFETYLEVEL;
    }
#endif /* SQLITE_DEFAULT_WAL_SAFETYLEVEL */
    for(ii=db->nDb-1; ii>=0; ii--){
      if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
        sqlite3VdbeUsesBtree(v, ii);
        sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode);
      }
    }
    sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
Changes to src/select.c.
4367
4368
4369
4370
4371
4372
4373



4374
4375
4376
4377
4378
4379
4380

  sqlite3DbFree(db, sAggInfo.aCol);
  sqlite3DbFree(db, sAggInfo.aFunc);
  return rc;
}

#if defined(SQLITE_DEBUG)



/*
*******************************************************************************
** The following code is used for testing and debugging only.  The code
** that follows does not appear in normal builds.
**
** These routines are used to print out the content of all or part of a 
** parse structures such as Select or Expr.  Such printouts are useful







>
>
>







4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383

  sqlite3DbFree(db, sAggInfo.aCol);
  sqlite3DbFree(db, sAggInfo.aFunc);
  return rc;
}

#if defined(SQLITE_DEBUG)
void sqlite3PrintExpr(Expr *p);
void sqlite3PrintExprList(ExprList *pList);
void sqlite3PrintSelect(Select *p, int indent);
/*
*******************************************************************************
** The following code is used for testing and debugging only.  The code
** that follows does not appear in normal builds.
**
** These routines are used to print out the content of all or part of a 
** parse structures such as Select or Expr.  Such printouts are useful
Changes to src/sqlite.h.in.
60
61
62
63
64
65
66



67
68
69
70
71
72
73
** would generate warning messages when they were used.  But that
** compiler magic ended up generating such a flurry of bug reports
** that we have taken it all out and gone back to using simple
** noop macros.
*/
#define SQLITE_DEPRECATED
#define SQLITE_EXPERIMENTAL




/*
** Ensure these symbols were not defined by some previous header file.
*/
#ifdef SQLITE_VERSION
# undef SQLITE_VERSION
#endif







>
>
>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
** would generate warning messages when they were used.  But that
** compiler magic ended up generating such a flurry of bug reports
** that we have taken it all out and gone back to using simple
** noop macros.
*/
#define SQLITE_DEPRECATED
#define SQLITE_EXPERIMENTAL
#ifndef __OSX_AVAILABLE_BUT_DEPRECATED
#define __OSX_AVAILABLE_BUT_DEPRECATED(MacOSAvailable, MacOSDeprecated, iPhoneOSAvailable, iPhoneOSDeprecated)
#endif

/*
** Ensure these symbols were not defined by some previous header file.
*/
#ifdef SQLITE_VERSION
# undef SQLITE_VERSION
#endif
479
480
481
482
483
484
485

486
487
488
489
490
491
492
#define SQLITE_OPEN_SUBJOURNAL       0x00002000  /* VFS only */
#define SQLITE_OPEN_MASTER_JOURNAL   0x00004000  /* VFS only */
#define SQLITE_OPEN_NOMUTEX          0x00008000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_FULLMUTEX        0x00010000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE      0x00020000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE     0x00040000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL              0x00080000  /* VFS only */


/* Reserved:                         0x00F00000 */

/*
** CAPI3REF: Device Characteristics
**
** The xDeviceCharacteristics method of the [sqlite3_io_methods]







>







482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
#define SQLITE_OPEN_SUBJOURNAL       0x00002000  /* VFS only */
#define SQLITE_OPEN_MASTER_JOURNAL   0x00004000  /* VFS only */
#define SQLITE_OPEN_NOMUTEX          0x00008000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_FULLMUTEX        0x00010000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE      0x00020000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE     0x00040000  /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL              0x00080000  /* VFS only */
#define SQLITE_OPEN_FILEPROTECTION_MASK                                 0x00700000

/* Reserved:                         0x00F00000 */

/*
** CAPI3REF: Device Characteristics
**
** The xDeviceCharacteristics method of the [sqlite3_io_methods]
4451
4452
4453
4454
4455
4456
4457





4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled
** successfully.  An [error code] is returned otherwise.)^
**
** ^Shared cache is disabled by default. But this might change in
** future releases of SQLite.  Applications that care about shared
** cache setting should set it explicitly.
**





** See Also:  [SQLite Shared-Cache Mode]
*/
int sqlite3_enable_shared_cache(int);

/*
** CAPI3REF: Attempt To Free Heap Memory
**
** ^The sqlite3_release_memory() interface attempts to free N bytes
** of heap memory by deallocating non-essential memory allocations
** held by the database library.   Memory used to cache database







>
>
>
>
>


|







4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled
** successfully.  An [error code] is returned otherwise.)^
**
** ^Shared cache is disabled by default. But this might change in
** future releases of SQLite.  Applications that care about shared
** cache setting should set it explicitly.
**
** ^Note: This method is deprecated on MacOS X 10.7 and iOS version 5.0
** and will always return SQLITE_MISUSE, instead of calling this function
** shared cache mode should be enabled per-database connection via 
** sqlite3_open_v2 with SQLITE_OPEN_SHAREDCACHE instead.
**
** See Also:  [SQLite Shared-Cache Mode]
*/
int sqlite3_enable_shared_cache(int) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_7, __IPHONE_2_0, __IPHONE_5_0);

/*
** CAPI3REF: Attempt To Free Heap Memory
**
** ^The sqlite3_release_memory() interface attempts to free N bytes
** of heap memory by deallocating non-essential memory allocations
** held by the database library.   Memory used to cache database
Changes to src/sqlite3_private.h.
1
2
3
4
5
6
7






















8
9
10
11
12
13
14
/*
 *  sqlite3_private.h
 */

#ifndef _SQLITE3_PRIVATE_H
#define _SQLITE3_PRIVATE_H























/*
** 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

/*







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*
 *  sqlite3_private.h
 */

#ifndef _SQLITE3_PRIVATE_H
#define _SQLITE3_PRIVATE_H

#define SQLITE_LOCKSTATE_OFF    0
#define SQLITE_LOCKSTATE_ON     1
#define SQLITE_LOCKSTATE_NOTADB 2
#define SQLITE_LOCKSTATE_ERROR  -1

#define SQLITE_LOCKSTATE_ANYPID -1

/* 
** Test a file path for sqlite locks held by a process ID (-1 = any PID). 
** Returns one of the following integer codes:
** 
**   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
**
** There is no support for identifying db files encrypted via SEE encryption
** currently.  Zero byte files are tested for sqlite locks, but if no sqlite 
** locks are present then SQLITE_LOCKSTATE_NOTADB is returned.
*/
extern int _sqlite3_lockstate(const char *path, pid_t pid);

/*
** 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

/*
Changes to src/test1.c.
4964
4965
4966
4967
4968
4969
4970













































































4971
4972
4973
4974
4975
4976
4977
    Tcl_AppendResult(interp, "Unexpected non-zero errno: ",
                     Tcl_GetStringFromObj(Tcl_NewIntObj(iArg), 0), " ", 0);
    return TCL_ERROR;
  }
  return TCL_OK;  
}














































































/*
** tclcmd:   file_control_chunksize_test DB DBNAME SIZE
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
** SQLITE_SET_LOCKPROXYFILE verbs.
*/







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
    Tcl_AppendResult(interp, "Unexpected non-zero errno: ",
                     Tcl_GetStringFromObj(Tcl_NewIntObj(iArg), 0), " ", 0);
    return TCL_ERROR;
  }
  return TCL_OK;  
}

#ifdef __APPLE__
/* From sqlite3_priavet.h */
# ifndef SQLITE_TRUNCATE_DATABASE
# define SQLITE_TRUNCATE_DATABASE      101
# endif
# ifndef SQLITE_REPLACE_DATABASE
# define SQLITE_REPLACE_DATABASE       102
# endif

/*
** tclcmd:   file_control_truncate_test DB
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_TRUNCATE_DATABASE verb.
*/
static int file_control_truncate_test(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3 *db;
  int rc;
  
  if( objc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
                     Tcl_GetStringFromObj(objv[0], 0), " DB", 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( rc ){ 
    Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 
    return TCL_ERROR; 
  }
  return TCL_OK;  
}

/*
** tclcmd:   file_control_replace_test DB
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_REPLACE_DATABASE verb.
*/
static int file_control_replace_test(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  int iArg = 0;
  sqlite3 *src_db;
  sqlite3 *dst_db;
  int rc;
  
  if( objc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
                     Tcl_GetStringFromObj(objv[0], 0), " DST_DB SRC_DB", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &dst_db) ){
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[2]), &src_db) ){
    return TCL_ERROR;
  }
  rc = sqlite3_file_control(dst_db, NULL, SQLITE_REPLACE_DATABASE, src_db);
  if( rc ){ 
    Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); 
    return TCL_ERROR; 
  }
  return TCL_OK;  
}
#endif /* __APPLE__ */

/*
** tclcmd:   file_control_chunksize_test DB DBNAME SIZE
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
** SQLITE_SET_LOCKPROXYFILE verbs.
*/
5907
5908
5909
5910
5911
5912
5913




5914
5915
5916
5917
5918
5919
5920
     { "vfs_unlink_test",            vfs_unlink_test,     0   },
     { "vfs_initfail_test",          vfs_initfail_test,   0   },
     { "vfs_unregister_all",         vfs_unregister_all,  0   },
     { "vfs_reregister_all",         vfs_reregister_all,  0   },
     { "file_control_test",          file_control_test,   0   },
     { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },




     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test", file_control_sizehint_test,  0   },
     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },
     { "path_is_local",              path_is_local,  0   },
     { "path_is_dos",                path_is_dos,  0   },








>
>
>
>







5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
     { "vfs_unlink_test",            vfs_unlink_test,     0   },
     { "vfs_initfail_test",          vfs_initfail_test,   0   },
     { "vfs_unregister_all",         vfs_unregister_all,  0   },
     { "vfs_reregister_all",         vfs_reregister_all,  0   },
     { "file_control_test",          file_control_test,   0   },
     { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
#ifdef __APPLE__
     { "file_control_truncate_test", file_control_truncate_test,  0   },
     { "file_control_replace_test", file_control_replace_test,  0   },
#endif 
     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test", file_control_sizehint_test,  0   },
     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },
     { "path_is_local",              path_is_local,  0   },
     { "path_is_dos",                path_is_dos,  0   },

Changes to src/test_config.c.
431
432
433
434
435
436
437
438










439
440
441
442
443
444
445
  Tcl_SetVar2(interp,"sqlite_options","lock_proxy_pragmas","0",TCL_GLOBAL_ONLY);
#endif
#if defined(SQLITE_PREFER_PROXY_LOCKING) && defined(__APPLE__)
  Tcl_SetVar2(interp,"sqlite_options","prefer_proxy_locking","1",TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp,"sqlite_options","prefer_proxy_locking","0",TCL_GLOBAL_ONLY);
#endif
    










    
#ifdef SQLITE_OMIT_SHARED_CACHE
  Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "0", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "1", TCL_GLOBAL_ONLY);
#endif








|
>
>
>
>
>
>
>
>
>
>







431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
  Tcl_SetVar2(interp,"sqlite_options","lock_proxy_pragmas","0",TCL_GLOBAL_ONLY);
#endif
#if defined(SQLITE_PREFER_PROXY_LOCKING) && defined(__APPLE__)
  Tcl_SetVar2(interp,"sqlite_options","prefer_proxy_locking","1",TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp,"sqlite_options","prefer_proxy_locking","0",TCL_GLOBAL_ONLY);
#endif
#if SQLITE_DEFAULT_CKPTFULLFSYNC
  Tcl_SetVar2(interp,"sqlite_options","default_ckptfullfsync","1",TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp,"sqlite_options","default_ckptfullfsync","0",TCL_GLOBAL_ONLY);
#endif
#if SQLITE_DEFAULT_WAL_SAFETYLEVEL
  Tcl_SetVar2(interp,"sqlite_options","default_wal_safetylevel",
              STRINGVALUE(SQLITE_DEFAULT_WAL_SAFETYLEVEL),TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp,"sqlite_options","default_wal_safetylevel","0",TCL_GLOBAL_ONLY);
#endif
    
#ifdef SQLITE_OMIT_SHARED_CACHE
  Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "0", TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp, "sqlite_options", "shared_cache", "1", TCL_GLOBAL_ONLY);
#endif

Changes to src/test_rtree.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library. 
*/

#include <sqlite3.h>

/* Solely for the UNUSED_PARAMETER() macro. */
#include "sqliteInt.h"

/* 
** Type used to cache parameter information for the "circle" r-tree geometry
** callback.







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library. 
*/

#include "sqlite3.h"

/* Solely for the UNUSED_PARAMETER() macro. */
#include "sqliteInt.h"

/* 
** Type used to cache parameter information for the "circle" r-tree geometry
** callback.
Changes to src/test_superlock.c.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** mode database files. The interface to the example code in this file 
** consists of the following two functions:
**
**   sqlite3demo_superlock()
**   sqlite3demo_superunlock()
*/

#include <sqlite3.h>
#include <string.h>               /* memset(), strlen() */
#include <assert.h>               /* assert() */

/*
** A structure to collect a busy-handler callback and argument and a count
** of the number of times it has been invoked.
*/







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** mode database files. The interface to the example code in this file 
** consists of the following two functions:
**
**   sqlite3demo_superlock()
**   sqlite3demo_superunlock()
*/

#include "sqlite3.h"
#include <string.h>               /* memset(), strlen() */
#include <assert.h>               /* assert() */

/*
** A structure to collect a busy-handler callback and argument and a count
** of the number of times it has been invoked.
*/
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
}

/*
** Release a superlock held on a database file. The argument passed to 
** this function must have been obtained from a successful call to
** sqlite3demo_superlock().
*/
void sqlite3demo_superunlock(void *pLock){
  Superlock *p = (Superlock *)pLock;
  if( p->bWal ){
    int rc;                         /* Return code */
    int flags = SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE;
    sqlite3_file *fd = 0;
    rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
    if( rc==SQLITE_OK ){







|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
}

/*
** Release a superlock held on a database file. The argument passed to 
** this function must have been obtained from a successful call to
** sqlite3demo_superlock().
*/
static void sqlite3demo_superunlock(void *pLock){
  Superlock *p = (Superlock *)pLock;
  if( p->bWal ){
    int rc;                         /* Return code */
    int flags = SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE;
    sqlite3_file *fd = 0;
    rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
    if( rc==SQLITE_OK ){
175
176
177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
**
** If a required lock cannot be obtained immediately and the xBusy parameter
** to this function is not NULL, then xBusy is invoked in the same way
** as a busy-handler registered with SQLite (using sqlite3_busy_handler())
** until either the lock can be obtained or the busy-handler function returns
** 0 (indicating "give up").
*/
int sqlite3demo_superlock(
  const char *zPath,              /* Path to database file to lock */
  const char *zVfs,               /* VFS to use to access database file */

  int (*xBusy)(void*,int),        /* Busy handler callback */
  void *pBusyArg,                 /* Context arg for busy handler */
  void **ppLock                   /* OUT: Context to pass to superunlock() */
){
  SuperlockBusy busy = {0, 0, 0}; /* Busy handler wrapper object */
  int rc;                         /* Return code */
  Superlock *pLock;

  pLock = sqlite3_malloc(sizeof(Superlock));
  if( !pLock ) return SQLITE_NOMEM;
  memset(pLock, 0, sizeof(Superlock));

  /* Open a database handle on the file to superlock. */
  rc = sqlite3_open_v2(
      zPath, &pLock->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs
  );

  /* Install a busy-handler and execute a BEGIN EXCLUSIVE. If this is not
  ** a WAL database, this is all we need to do.  
  **
  ** A wrapper function is used to invoke the busy-handler instead of
  ** registering the busy-handler function supplied by the user directly







|


>














|







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
**
** If a required lock cannot be obtained immediately and the xBusy parameter
** to this function is not NULL, then xBusy is invoked in the same way
** as a busy-handler registered with SQLite (using sqlite3_busy_handler())
** until either the lock can be obtained or the busy-handler function returns
** 0 (indicating "give up").
*/
static int sqlite3demo_superlock(
  const char *zPath,              /* Path to database file to lock */
  const char *zVfs,               /* VFS to use to access database file */
  int flags,                      /* Additional flags to pass to sqlite3_open_v2 */
  int (*xBusy)(void*,int),        /* Busy handler callback */
  void *pBusyArg,                 /* Context arg for busy handler */
  void **ppLock                   /* OUT: Context to pass to superunlock() */
){
  SuperlockBusy busy = {0, 0, 0}; /* Busy handler wrapper object */
  int rc;                         /* Return code */
  Superlock *pLock;

  pLock = sqlite3_malloc(sizeof(Superlock));
  if( !pLock ) return SQLITE_NOMEM;
  memset(pLock, 0, sizeof(Superlock));

  /* Open a database handle on the file to superlock. */
  rc = sqlite3_open_v2(
    zPath, &pLock->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|flags, zVfs
  );

  /* Install a busy-handler and execute a BEGIN EXCLUSIVE. If this is not
  ** a WAL database, this is all we need to do.  
  **
  ** A wrapper function is used to invoke the busy-handler instead of
  ** registering the busy-handler function supplied by the user directly
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  }
  if( objc>4 ){
    busy.interp = interp;
    busy.pScript = objv[4];
    xBusy = superlock_busy;
  }

  rc = sqlite3demo_superlock(zPath, zVfs, xBusy, &busy, &pLock);
  assert( rc==SQLITE_OK || pLock==0 );
  assert( rc!=SQLITE_OK || pLock!=0 );

  if( rc!=SQLITE_OK ){
    extern const char *sqlite3ErrStr(int);
    Tcl_ResetResult(interp);
    Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);







|







328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
  }
  if( objc>4 ){
    busy.interp = interp;
    busy.pScript = objv[4];
    xBusy = superlock_busy;
  }

  rc = sqlite3demo_superlock(zPath, zVfs, 0, xBusy, &busy, &pLock);
  assert( rc==SQLITE_OK || pLock==0 );
  assert( rc!=SQLITE_OK || pLock!=0 );

  if( rc!=SQLITE_OK ){
    extern const char *sqlite3ErrStr(int);
    Tcl_ResetResult(interp);
    Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
Changes to src/vdbetrace.c.
79
80
81
82
83
84
85


86
87

88
89
90
91
92
93
94
95
  db = p->db;
  sqlite3StrAccumInit(&out, zBase, sizeof(zBase), 
                      db->aLimit[SQLITE_LIMIT_LENGTH]);
  out.db = db;
  if( db->vdbeExecCnt>1 ){
    while( *zRawSql ){
      const char *zStart = zRawSql;


      while( *(zRawSql++)!='\n' && *zRawSql );
      sqlite3StrAccumAppend(&out, "-- ", 3);

      sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
    }
  }else{
    while( zRawSql[0] ){
      n = findNextHostParameter(zRawSql, &nToken);
      assert( n>0 );
      sqlite3StrAccumAppend(&out, zRawSql, n);
      zRawSql += n;







>
>


>
|







79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  db = p->db;
  sqlite3StrAccumInit(&out, zBase, sizeof(zBase), 
                      db->aLimit[SQLITE_LIMIT_LENGTH]);
  out.db = db;
  if( db->vdbeExecCnt>1 ){
    while( *zRawSql ){
      const char *zStart = zRawSql;
      sqlite_int64 iStart = SQLITE_PTR_TO_INT(zRawSql);
      sqlite_int64 iCurrent;
      while( *(zRawSql++)!='\n' && *zRawSql );
      sqlite3StrAccumAppend(&out, "-- ", 3);
      iCurrent = SQLITE_PTR_TO_INT(zRawSql);
      sqlite3StrAccumAppend(&out, zStart, (int)(iCurrent-iStart));
    }
  }else{
    while( zRawSql[0] ){
      n = findNextHostParameter(zRawSql, &nToken);
      assert( n>0 );
      sqlite3StrAccumAppend(&out, zRawSql, n);
      zRawSql += n;
Changes to src/wal.c.
1243
1244
1245
1246
1247
1248
1249

1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
*/
int sqlite3WalOpen(
  sqlite3_vfs *pVfs,              /* vfs module to open wal and wal-index */
  sqlite3_file *pDbFd,            /* The open database file */
  const char *zWalName,           /* Name of the WAL file */
  int bNoShm,                     /* True to run in heap-memory mode */
  i64 mxWalSize,                  /* Truncate WAL to this size on reset */

  Wal **ppWal                     /* OUT: Allocated Wal handle */
){
  int rc;                         /* Return Code */
  Wal *pRet;                      /* Object to allocate and return */
  int flags;                      /* Flags passed to OsOpen() */

  assert( zWalName && zWalName[0] );
  assert( pDbFd );

  /* In the amalgamation, the os_unix.c and os_win.c source files come before
  ** this source file.  Verify that the #defines of the locking byte offsets
  ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.







>




|







1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
*/
int sqlite3WalOpen(
  sqlite3_vfs *pVfs,              /* vfs module to open wal and wal-index */
  sqlite3_file *pDbFd,            /* The open database file */
  const char *zWalName,           /* Name of the WAL file */
  int bNoShm,                     /* True to run in heap-memory mode */
  i64 mxWalSize,                  /* Truncate WAL to this size on reset */
  int flags,                      /* VFS file protection flags */
  Wal **ppWal                     /* OUT: Allocated Wal handle */
){
  int rc;                         /* Return Code */
  Wal *pRet;                      /* Object to allocate and return */
  int vfsFlags;                   /* Flags passed to OsOpen() */

  assert( zWalName && zWalName[0] );
  assert( pDbFd );

  /* In the amalgamation, the os_unix.c and os_win.c source files come before
  ** this source file.  Verify that the #defines of the locking byte offsets
  ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
  pRet->pDbFd = pDbFd;
  pRet->readLock = -1;
  pRet->mxWalSize = mxWalSize;
  pRet->zWalName = zWalName;
  pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);

  /* 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 ){
    pRet->readOnly = WAL_RDONLY;
  }

  if( rc!=SQLITE_OK ){
    walIndexClose(pRet, 0);
    sqlite3OsClose(pRet->pWalFd);
    sqlite3_free(pRet);







|
|
|







1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
  pRet->pDbFd = pDbFd;
  pRet->readLock = -1;
  pRet->mxWalSize = mxWalSize;
  pRet->zWalName = zWalName;
  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);
  rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, vfsFlags, &vfsFlags);
  if( rc==SQLITE_OK && vfsFlags&SQLITE_OPEN_READONLY ){
    pRet->readOnly = WAL_RDONLY;
  }

  if( rc!=SQLITE_OK ){
    walIndexClose(pRet, 0);
    sqlite3OsClose(pRet->pWalFd);
    sqlite3_free(pRet);
Changes to src/wal.h.
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

/* Connection to a write-ahead log (WAL) file. 
** There is one object of this type for each pager. 
*/
typedef struct Wal Wal;

/* Open and close a connection to a write-ahead log. */
int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);

/* Set the limiting size of a WAL file. */
void sqlite3WalLimit(Wal*, i64);

/* Used by readers to open (lock) and close (unlock) a snapshot.  A 
** snapshot is like a read-transaction.  It is the state of the database







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

/* Connection to a write-ahead log (WAL) file. 
** There is one object of this type for each pager. 
*/
typedef struct Wal Wal;

/* Open and close a connection to a write-ahead log. */
int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, int, Wal**);
int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);

/* Set the limiting size of a WAL file. */
void sqlite3WalLimit(Wal*, i64);

/* Used by readers to open (lock) and close (unlock) a snapshot.  A 
** snapshot is like a read-transaction.  It is the state of the database
Changes to test/fallocate.test.
77
78
79
80
81
82
83

84
85
86
87
88
89
90
}]
ifcapable !wal { set skipwaltests 1 }
if {![wal_is_ok]} { set skipwaltests 1 }

if {!$skipwaltests} {
  db close
  file delete -force test.db

  sqlite3 db test.db
  file_control_chunksize_test db main [expr 32*1024]
  
  do_test fallocate-2.1 {
    execsql {
      PRAGMA page_size = 1024;
      PRAGMA journal_mode = WAL;







>







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
}]
ifcapable !wal { set skipwaltests 1 }
if {![wal_is_ok]} { set skipwaltests 1 }

if {!$skipwaltests} {
  db close
  file delete -force test.db
  if {[forced_proxy_locking]} { file delete -force .test.db-conch }
  sqlite3 db test.db
  file_control_chunksize_test db main [expr 32*1024]
  
  do_test fallocate-2.1 {
    execsql {
      PRAGMA page_size = 1024;
      PRAGMA journal_mode = WAL;
Changes to test/incrblob3.test.
256
257
258
259
260
261
262




263
264
265
266
267
268

269
270
271
272
  set dbversion [hexio_get_int [hexio_read test.db 24 4]]
  incr dbversion
  hexio_write test.db 24 [hexio_render_int32 $dbversion]

  return ""
}





do_test incrblob3-7.2 {
  sqlite3 db test.db 
  sqlite3_db_config_lookaside db 0 0 0
  list [catch {db incrblob blobs v 1} msg] $msg
} {1 {database schema has changed}}
db close

tvfs delete

finish_test








>
>
>
>
|
|
|
|
|
|
>




256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  set dbversion [hexio_get_int [hexio_read test.db 24 4]]
  incr dbversion
  hexio_write test.db 24 [hexio_render_int32 $dbversion]

  return ""
}

#set sqlite_os_trace 1
# AFP asserts because the "db incrblob blobs v 1" clears the file locks and the unlock fails (HFS doesn't care about a failed unlock)
if {[path_is_local "."]} {

  do_test incrblob3-7.2 {
    sqlite3 db test.db 
    sqlite3_db_config_lookaside db 0 0 0
    list [catch {db incrblob blobs v 1} msg] $msg
  } {1 {database schema has changed}}
  db close
}
tvfs delete

finish_test

Changes to test/multiplex.test.
9
10
11
12
13
14
15






16
17
18
19
20
21
22
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl







set g_chunk_size [ expr ($::SQLITE_MAX_PAGE_SIZE*16384) ]
set g_max_chunks 32

# This handles appending the chunk number
# to the end of the filename.  if 
# SQLITE_MULTIPLEX_EXT_OVWR is defined, then







>
>
>
>
>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl

# AFP doesn't like multiplex db tests
if { ![path_is_local "."] } {
  finish_test 
  return 
}

set g_chunk_size [ expr ($::SQLITE_MAX_PAGE_SIZE*16384) ]
set g_max_chunks 32

# This handles appending the chunk number
# to the end of the filename.  if 
# SQLITE_MULTIPLEX_EXT_OVWR is defined, then
Changes to test/pager1.test.
530
531
532
533
534
535
536


537
538
539
540
541
542
543
    set ::mj_filename_length [string length $filename]
    faultsim_save 
  }
  return SQLITE_OK
}

set pwd [pwd]


foreach {tn1 tcl} {
  1 { set prefix "test.db" }
  2 { 
    # This test depends on the underlying VFS being able to open paths
    # 512 bytes in length. The idea is to create a hot-journal file that
    # contains a master-journal pointer so large that it could contain
    # a valid page record (if the file page-size is 512 bytes). So as to







>
>







530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
    set ::mj_filename_length [string length $filename]
    faultsim_save 
  }
  return SQLITE_OK
}

set pwd [pwd]
if {![forced_proxy_locking]} {
  # proxy locking uses can't deal with auto proxy file paths longer than MAXPATHLEN
foreach {tn1 tcl} {
  1 { set prefix "test.db" }
  2 { 
    # This test depends on the underlying VFS being able to open paths
    # 512 bytes in length. The idea is to create a hot-journal file that
    # contains a master-journal pointer so large that it could contain
    # a valid page record (if the file page-size is 512 bytes). So as to
661
662
663
664
665
666
667

668
669
670
671
672
673
674
  }

  cd $pwd
}
db close
tv delete
file delete -force $dirname



# Set up a VFS to make a copy of the file-system just before deleting a
# journal file to commit a transaction. The transaction modifies exactly
# two database pages (and page 1 - the change counter).
#
testvfs tv -default 1







>







663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
  }

  cd $pwd
}
db close
tv delete
file delete -force $dirname
}


# Set up a VFS to make a copy of the file-system just before deleting a
# journal file to commit a transaction. The transaction modifies exactly
# two database pages (and page 1 - the change counter).
#
testvfs tv -default 1
2004
2005
2006
2007
2008
2009
2010
2011
2012

2013
2014
2015
2016
2017
2018
2019
  testvfs tv -default 1
  tv filter xSync
  tv script xSyncCb
  proc xSyncCb {args} {incr ::synccount}
  set ::synccount 0
  sqlite3 db test.db
  execsql {
    PRAGMA synchronous = off;
    PRAGMA journal_mode = WAL;

    INSERT INTO ko DEFAULT VALUES;
  }
  execsql { PRAGMA wal_checkpoint }
  set synccount
} {0}
db close
tv delete







<

>







2007
2008
2009
2010
2011
2012
2013

2014
2015
2016
2017
2018
2019
2020
2021
2022
  testvfs tv -default 1
  tv filter xSync
  tv script xSyncCb
  proc xSyncCb {args} {incr ::synccount}
  set ::synccount 0
  sqlite3 db test.db
  execsql {

    PRAGMA journal_mode = WAL;
    PRAGMA synchronous = off;
    INSERT INTO ko DEFAULT VALUES;
  }
  execsql { PRAGMA wal_checkpoint }
  set synccount
} {0}
db close
tv delete
Changes to test/pragma.test.
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
    sqlite3 db2 test.db
    execsql "PRAGMA lock_proxy_file='$lpp2'" db2
    catchsql {
      select * from sqlite_master;
    } db2
  } {1 {database is locked}}

  set lpp3 [exec mktemp -t 'proxy3']

  # lock proxy file can be renamed if no other connections are active
  do_test pragma-16.4 {
    db2 close
    db close
    sqlite3 db2 test.db
    execsql "PRAGMA lock_proxy_file='$lpp3'" db2







|







1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
    sqlite3 db2 test.db
    execsql "PRAGMA lock_proxy_file='$lpp2'" db2
    catchsql {
      select * from sqlite_master;
    } db2
  } {1 {database is locked}}

  set lpp3 [exec mktemp -t "proxy3"]

  # lock proxy file can be renamed if no other connections are active
  do_test pragma-16.4 {
    db2 close
    db close
    sqlite3 db2 test.db
    execsql "PRAGMA lock_proxy_file='$lpp3'" db2
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
    list [catch {
      sqlite3 db test2.db
      execsql { select * from sqlite_master } 
    } msg] $msg
  } {1 {database is locked}}

  db2 close
  set lpp4 [exec mktemp -t 'proxy4']

  # check that db is unlocked after first host connection closes 
  do_test pragma-16.8.1 {
    execsql "PRAGMA lock_proxy_file='$lpp4'" 
    execsql "select * from sqlite_master"
    execsql "PRAGMA lock_proxy_file"
  } $lpp4







|







1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
    list [catch {
      sqlite3 db test2.db
      execsql { select * from sqlite_master } 
    } msg] $msg
  } {1 {database is locked}}

  db2 close
  set lpp4 [exec mktemp -t "proxy4"]

  # check that db is unlocked after first host connection closes 
  do_test pragma-16.8.1 {
    execsql "PRAGMA lock_proxy_file='$lpp4'" 
    execsql "select * from sqlite_master"
    execsql "PRAGMA lock_proxy_file"
  } $lpp4
1429
1430
1431
1432
1433
1434
1435
1436

1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479

1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
      PRAGMA lock_proxy_file=":auto:";
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest.db:auto:" $lockpath2
  } {1}

  # ensure creating directories for a lock proxy file works
  set lpp5 [exec mktemp -d -t "proxy5"]/sub/dir/lock

  db close
  file delete -force proxytest
  do_test pragma-16.10.1 {
    sqlite3 db proxytest.db
    execsql "PRAGMA lock_proxy_file='$lpp5'" 
    set lockpath2 [execsql {
      PRAGMA lock_proxy_file;
    } db]
    string match "*sub/dir/lock" $lockpath2
  } {1}

  # ensure that after deleting the path, setting ":auto:" works correctly
  db close
  file delete -force proxytest
  do_test pragma-16.10.2 {
    sqlite3 db proxytest.db
    set lockpath3 [execsql {
      PRAGMA lock_proxy_file=":auto:";
      create table if not exists pt(y);
      PRAGMA lock_proxy_file;
    } db]
    string match "*sub/dir/lock" $lockpath3
  } {1}

  # ensure that if the path can not be created (file instead of dir)
  # setting :auto: deals with it by creating a new autonamed lock file
  db close
  file delete -force proxytest
  close [open "proxytest" a]
  do_test pragma-16.10.3 {
    sqlite3 db proxytest.db
    set lockpath2 [execsql {
      PRAGMA lock_proxy_file=":auto:";
      create table if not exists zz(y);
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest.db:auto:" $lockpath2
  } {1}

  # make sure we can deal with ugly file paths correctly
  set lpp6 [exec mktemp -d -t "proxy6"]/./././////./proxytest/../proxytest/sub/dir/lock
  db close
  file delete -force proxytest

  do_test pragma-16.10.4 {
    sqlite3 db proxytest.db
    execsql "PRAGMA lock_proxy_file='$lpp6'" 
    set lockpath4 [execsql {
      create table if not exists aa(bb);
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest/sub/dir/lock" $lockpath4
  } {1}

  # ensure that if the path can not be created (perm), setting :auto: deals
  db close
  file delete -force proxytest
  do_test pragma-16.10.5 {
    sqlite3 db proxytest.db
    execsql "PRAGMA lock_proxy_file='$lpp5'" 
    execsql {
      create table if not exists bb(bb);
    }
    db close
    file delete -force proxytest
    file mkdir proxytest
    file attributes proxytest -permission 0000
    sqlite3 db proxytest.db
    set lockpath5 [execsql {
      PRAGMA lock_proxy_file=":auto:";
      create table if not exists cc(bb);
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest.db:auto:" $lockpath5







|
>

<











|













|
|











<

|
>












|







|
|
|







1429
1430
1431
1432
1433
1434
1435
1436
1437
1438

1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476

1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
      PRAGMA lock_proxy_file=":auto:";
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest.db:auto:" $lockpath2
  } {1}

  # ensure creating directories for a lock proxy file works
  set lpp5d [exec mktemp -d -t "proxy5"]
  set lpp5 $lpp5d/sub/dir/lock
  db close

  do_test pragma-16.10.1 {
    sqlite3 db proxytest.db
    execsql "PRAGMA lock_proxy_file='$lpp5'" 
    set lockpath2 [execsql {
      PRAGMA lock_proxy_file;
    } db]
    string match "*sub/dir/lock" $lockpath2
  } {1}

  # ensure that after deleting the path, setting ":auto:" works correctly
  db close
  file delete -force $lpp5d
  do_test pragma-16.10.2 {
    sqlite3 db proxytest.db
    set lockpath3 [execsql {
      PRAGMA lock_proxy_file=":auto:";
      create table if not exists pt(y);
      PRAGMA lock_proxy_file;
    } db]
    string match "*sub/dir/lock" $lockpath3
  } {1}

  # ensure that if the path can not be created (file instead of dir)
  # setting :auto: deals with it by creating a new autonamed lock file
  db close
  file delete -force $lpp5d
  close [open "$lpp5d" a]
  do_test pragma-16.10.3 {
    sqlite3 db proxytest.db
    set lockpath2 [execsql {
      PRAGMA lock_proxy_file=":auto:";
      create table if not exists zz(y);
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest.db:auto:" $lockpath2
  } {1}

  # make sure we can deal with ugly file paths correctly

  db close
  file delete -force $lpp5d
  set lpp6 [exec mktemp -d -t "proxy6"]/./././////./proxytest/../proxytest/sub/dir/lock
  do_test pragma-16.10.4 {
    sqlite3 db proxytest.db
    execsql "PRAGMA lock_proxy_file='$lpp6'" 
    set lockpath4 [execsql {
      create table if not exists aa(bb);
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest/sub/dir/lock" $lockpath4
  } {1}

  # ensure that if the path can not be created (perm), setting :auto: deals
  db close
  file delete -force $lpp5d
  do_test pragma-16.10.5 {
    sqlite3 db proxytest.db
    execsql "PRAGMA lock_proxy_file='$lpp5'" 
    execsql {
      create table if not exists bb(bb);
    }
    db close
    file delete -force $lpp5d
    file mkdir $lpp5d
    file attributes $lpp5d -permission 0000
    sqlite3 db proxytest.db
    set lockpath5 [execsql {
      PRAGMA lock_proxy_file=":auto:";
      create table if not exists cc(bb);
      PRAGMA lock_proxy_file;
    } db]
    string match "*proxytest.db:auto:" $lockpath5
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
    catchsql {
      create table if not exists faily(y);
      PRAGMA lock_proxy_file;
    } db
  } {1 {database is locked}}
  db close

  file attributes proxytest -permission 0777
  file delete -force proxytest

  set env(SQLITE_FORCE_PROXY_LOCKING) $using_proxy
  set sqlite_hostid_num 0
}

# Parsing of auto_vacuum settings.
#







|
|







1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
    catchsql {
      create table if not exists faily(y);
      PRAGMA lock_proxy_file;
    } db
  } {1 {database is locked}}
  db close

  file attributes $lpp5d -permission 0777
  file delete -force $lpp5d

  set env(SQLITE_FORCE_PROXY_LOCKING) $using_proxy
  set sqlite_hostid_num 0
}

# Parsing of auto_vacuum settings.
#
Changes to test/superlock.test.
47
48
49
50
51
52
53






54
55
56
57
58
59
60
  INSERT INTO t1 VALUES(1, 2);
  PRAGMA journal_mode = DELETE;
} {delete}

do_test 1.2 { sqlite3demo_superlock unlock test.db } {unlock}
do_catchsql_test 1.3 { SELECT * FROM t1 } {1 {database is locked}}
do_test 1.4 { unlock } {}







do_execsql_test 2.1 { 
  INSERT INTO t1 VALUES(3, 4);
  PRAGMA journal_mode = WAL;
} {wal}

do_test 2.2 { sqlite3demo_superlock unlock test.db } {unlock}







>
>
>
>
>
>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  INSERT INTO t1 VALUES(1, 2);
  PRAGMA journal_mode = DELETE;
} {delete}

do_test 1.2 { sqlite3demo_superlock unlock test.db } {unlock}
do_catchsql_test 1.3 { SELECT * FROM t1 } {1 {database is locked}}
do_test 1.4 { unlock } {}

ifcapable !wal {finish_test ; return }
if { ![wal_is_ok] } {
  finish_test 
  return 
}

do_execsql_test 2.1 { 
  INSERT INTO t1 VALUES(3, 4);
  PRAGMA journal_mode = WAL;
} {wal}

do_test 2.2 { sqlite3demo_superlock unlock test.db } {unlock}
Changes to test/tester.tcl.
237
238
239
240
241
242
243

















244
245
246
247
248
249
250
251








252
253
254
255
256
257
258
}

# Update the soft-heap-limit each time this script is run. In that
# way if an individual test file changes the soft-heap-limit, it
# will be reset at the start of the next test file.
#
sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)


















# Create a test database
#
proc reset_db {} {
  catch {db close}
  file delete -force test.db
  file delete -force test.db-journal
  file delete -force test.db-wal








  sqlite3 db ./test.db
  set ::DB [sqlite3_connection_pointer db]
  if {[info exists ::SETUP_SQL]} {
    db eval $::SETUP_SQL
  }
}
reset_db







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








>
>
>
>
>
>
>
>







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
}

# Update the soft-heap-limit each time this script is run. In that
# way if an individual test file changes the soft-heap-limit, it
# will be reset at the start of the next test file.
#
sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)

proc forced_proxy_locking {} {
  if $::sqlite_options(lock_proxy_pragmas)&&$::sqlite_options(prefer_proxy_locking) {
    set force_proxy_value 0
    set force_key "SQLITE_FORCE_PROXY_LOCKING="
    foreach {env_pair} [exec env] { 
      if { [string first $force_key $env_pair] == 0} {
        set force_proxy_value [string range $env_pair [string length $force_key] end]
      }
    }
    if { "$force_proxy_value " == "1 " } {
      return 1
    } 
  }
  return 0
}


# Create a test database
#
proc reset_db {} {
  catch {db close}
  file delete -force test.db
  file delete -force test.db-journal
  file delete -force test.db-wal
  if {[forced_proxy_locking]} {
    sqlite3 db ./test.db
    set lock_proxy_path [db eval "PRAGMA lock_proxy_file;"] 
    catch {db close}
    # puts "deleting $lock_proxy_path"
    file delete -force $lock_proxy_path    
    file delete -force test.db
  }
  sqlite3 db ./test.db
  set ::DB [sqlite3_connection_pointer db]
  if {[info exists ::SETUP_SQL]} {
    db eval $::SETUP_SQL
  }
}
reset_db
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
}
proc presql {} {
  set presql ""
  catch {set presql $::G(perm:presql)}
  set presql
}

proc forced_proxy_locking {} {
  ifcapable lock_proxy_pragmas&&prefer_proxy_locking {
    set force_proxy_value 0
    set force_key "SQLITE_FORCE_PROXY_LOCKING="
    foreach {env_pair} [exec env] { 
      if { [string first $force_key $env_pair] == 0} {
        set force_proxy_value [string range $env_pair [string length $force_key] end]
      }
    }
    if { "$force_proxy_value " == "1 " } {
      return 1
    } 
  }
  return 0
}

proc wal_is_ok {} {
  if { [forced_proxy_locking] } {
    return 1
  }
  if { ![path_is_local "."] } {
    return 0
  }







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1355
1356
1357
1358
1359
1360
1361
















1362
1363
1364
1365
1366
1367
1368
}
proc presql {} {
  set presql ""
  catch {set presql $::G(perm:presql)}
  set presql
}

















proc wal_is_ok {} {
  if { [forced_proxy_locking] } {
    return 1
  }
  if { ![path_is_local "."] } {
    return 0
  }
Changes to test/wal2.test.
1179
1180
1181
1182
1183
1184
1185





1186
1187
1188
1189
1190
1191
1192
# Test that "PRAGMA checkpoint_fullsync" appears to be working.
#
foreach {tn sql reslist} {
  1 { }                                 {8 0 3 0 5 0}
  2 { PRAGMA checkpoint_fullfsync = 1 } {8 4 3 2 5 2}
  3 { PRAGMA checkpoint_fullfsync = 0 } {8 0 3 0 5 0}
} {





  faultsim_delete_and_reopen

  execsql {PRAGMA auto_vacuum = 0}
  execsql $sql
  do_execsql_test wal2-14.$tn.1 { PRAGMA journal_mode = WAL } {wal}

  set sqlite_sync_count 0







>
>
>
>
>







1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
# Test that "PRAGMA checkpoint_fullsync" appears to be working.
#
foreach {tn sql reslist} {
  1 { }                                 {8 0 3 0 5 0}
  2 { PRAGMA checkpoint_fullfsync = 1 } {8 4 3 2 5 2}
  3 { PRAGMA checkpoint_fullfsync = 0 } {8 0 3 0 5 0}
} {
  if { $::sqlite_options(default_ckptfullfsync) && $tn == 1} {
    # checkpoint_fullfsync on by default
    set reslist {8 4 3 2 5 2}
  }

  faultsim_delete_and_reopen

  execsql {PRAGMA auto_vacuum = 0}
  execsql $sql
  do_execsql_test wal2-14.$tn.1 { PRAGMA journal_mode = WAL } {wal}

  set sqlite_sync_count 0
Changes to test/wal3.test.
202
203
204
205
206
207
208










209
210
211
212
213
214
215
  1 off     
    {}
  2 normal  
    {test.db-wal normal test.db normal}
  3 full    
    {test.db-wal normal test.db-wal normal test.db-wal normal test.db normal}
} {











  proc sync_counter {args} { 
    foreach {method filename id flags} $args break
    lappend ::syncs [file tail $filename] $flags
  }
  do_test wal3-3.$tn {
    file delete -force test.db test.db-wal test.db-journal







>
>
>
>
>
>
>
>
>
>







202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  1 off     
    {}
  2 normal  
    {test.db-wal normal test.db normal}
  3 full    
    {test.db-wal normal test.db-wal normal test.db-wal normal test.db normal}
} {

  if { $::sqlite_options(default_ckptfullfsync) } {
    # checkpoint_fullfsync on by default
    if { $tn == 2} {
      set synccount {test.db-wal full test.db full}
    }
    if { $tn == 3} {
      set synccount {test.db-wal normal test.db-wal normal test.db-wal full test.db full}
    }
  }

  proc sync_counter {args} { 
    foreach {method filename id flags} $args break
    lappend ::syncs [file tail $filename] $flags
  }
  do_test wal3-3.$tn {
    file delete -force test.db test.db-wal test.db-journal
Changes to test/wal6.test.
15
16
17
18
19
20
21


22
23
24
25
26
27
28

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
source $testdir/malloc_common.tcl
ifcapable !wal {finish_test ; return }



#-------------------------------------------------------------------------
# Changing to WAL mode in one connection forces the change in others.
#
db close
forcedelete test.db








>
>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
source $testdir/malloc_common.tcl
ifcapable !wal {finish_test ; return }

if { ![wal_is_ok] } {finish_test ; return }

#-------------------------------------------------------------------------
# Changing to WAL mode in one connection forces the change in others.
#
db close
forcedelete test.db

Changes to test/walcrash2.test.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29


set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
ifcapable !wal {finish_test ; return }
if { ![wal_is_ok] } {
  finish_test 
  return 
}


#-------------------------------------------------------------------------
# This test case demonstrates a flaw in the wal-index manipulation that
# existed at one point: If a process crashes mid-transaction, it may have
# already added some entries to one of the hash-tables in the wal-index.
# If the transaction were to be explicitly rolled back at this point, the







|
<
<
<







12
13
14
15
16
17
18
19



20
21
22
23
24
25
26


set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
ifcapable !wal {finish_test ; return }
if { ![wal_is_ok] } { finish_test ; return }





#-------------------------------------------------------------------------
# This test case demonstrates a flaw in the wal-index manipulation that
# existed at one point: If a process crashes mid-transaction, it may have
# already added some entries to one of the hash-tables in the wal-index.
# If the transaction were to be explicitly rolled back at this point, the
Changes to test/walro.test.
19
20
21
22
23
24
25







26
27
28
29
30
31
32

# These tests are only going to work on unix.
#
if {$::tcl_platform(platform) != "unix"} {
  finish_test
  return
}








do_multiclient_test tn {
  # Do not run tests with the connections in the same process.
  #
  if {$tn==2} continue
  
  # Close all connections and delete the database.







>
>
>
>
>
>
>







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# These tests are only going to work on unix.
#
if {$::tcl_platform(platform) != "unix"} {
  finish_test
  return
}

# these tests can't deal with the location of the -shm file under proxy locking
#
if {[forced_proxy_locking]} {
  finish_test
  return
}

do_multiclient_test tn {
  # Do not run tests with the connections in the same process.
  #
  if {$tn==2} continue
  
  # Close all connections and delete the database.