SQLite

Check-in [6547929410]
Login

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

Overview
Comment:Added support for SQLITE_ENABLE_PERSIST_WAL compile time macro, retrieving lastErrno from WAL file and setting last errno when writes fail due to space constraints
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | apple-osx
Files: files | file ages | folders
SHA1: 654792941011c96db879f6b779e99b1c65c587af
User & Date: adam 2012-05-09 22:36:25.742
Context
2012-05-10
12:09
Merge in the legacy table constraint parsing fixes from trunk. (check-in: e87702834e user: drh tags: apple-osx)
2012-05-09
22:36
Added support for SQLITE_ENABLE_PERSIST_WAL compile time macro, retrieving lastErrno from WAL file and setting last errno when writes fail due to space constraints (check-in: 6547929410 user: adam tags: apple-osx)
2012-05-05
01:03
Merge the latest trunk changes into the apple-osx branch. (check-in: 2a99c0074a user: drh tags: apple-osx)
Changes
Unified Diff Ignore Whitespace Patch
Changes to Makefile.in.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

# The library that programs using readline() must link against.
#
LIBREADLINE = @TARGET_READLINE_LIBS@

# Should the database engine be compiled threadsafe
#
TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@

# Any target libraries which libsqlite must be linked against
# 
TLIBS = @LIBS@

# Flags controlling use of the in memory btree implementation
#







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

# The library that programs using readline() must link against.
#
LIBREADLINE = @TARGET_READLINE_LIBS@

# Should the database engine be compiled threadsafe
#
#TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@

# Any target libraries which libsqlite must be linked against
# 
TLIBS = @LIBS@

# Flags controlling use of the in memory btree implementation
#
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# This is the command to use for tclsh - normally just "tclsh", but we may
# know the specific version we want to use
#
TCLSH_CMD = @TCLSH_CMD@

# Where do we want to install the tcl plugin
#
TCLLIBDIR = @TCLLIBDIR@

# The suffix used on shared libraries.  Ex:  ".dll", ".so", ".dylib"
#
SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@

# If gcov support was enabled by the configure script, add the appropriate
# flags here.  It's not always as easy as just having the user add the right







|







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# This is the command to use for tclsh - normally just "tclsh", but we may
# know the specific version we want to use
#
TCLSH_CMD = @TCLSH_CMD@

# Where do we want to install the tcl plugin
#
TCLLIBDIR = /System/Library/Tcl

# The suffix used on shared libraries.  Ex:  ".dll", ".so", ".dylib"
#
SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@

# If gcov support was enabled by the configure script, add the appropriate
# flags here.  It's not always as easy as just having the user add the right
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
libsqlite3.la:	$(LIBOBJ)
	$(LTLINK) -o $@ $(LIBOBJ) $(TLIBS) \
		${ALLOWRELEASE} -rpath "$(libdir)" -version-info "8:6:8"

libtclsqlite3.la:	tclsqlite.lo libsqlite3.la
	$(LTLINK) -o $@ tclsqlite.lo \
		libsqlite3.la @TCL_STUB_LIB_SPEC@ $(TLIBS) \
		-rpath "$(TCLLIBDIR)" \
		-version-info "8:6:8" \
		-avoid-version

sqlite3$(TEXE):	$(TOP)/src/shell.c libsqlite3.la sqlite3.h
	$(LTLINK) $(READLINE_FLAGS) \
		-o $@ $(TOP)/src/shell.c libsqlite3.la \
		$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"

# This target creates a directory named "tsrc" and fills it with







|
|
<







501
502
503
504
505
506
507
508
509

510
511
512
513
514
515
516
libsqlite3.la:	$(LIBOBJ)
	$(LTLINK) -o $@ $(LIBOBJ) $(TLIBS) \
		${ALLOWRELEASE} -rpath "$(libdir)" -version-info "8:6:8"

libtclsqlite3.la:	tclsqlite.lo libsqlite3.la
	$(LTLINK) -o $@ tclsqlite.lo \
		libsqlite3.la @TCL_STUB_LIB_SPEC@ $(TLIBS) \
                -rpath "$(TCLLIBDIR)/sqlite3" \
		-version-info "8:6:8"


sqlite3$(TEXE):	$(TOP)/src/shell.c libsqlite3.la sqlite3.h
	$(LTLINK) $(READLINE_FLAGS) \
		-o $@ $(TOP)/src/shell.c libsqlite3.la \
		$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"

# This target creates a directory named "tsrc" and fills it with
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
	$(INSTALL) -d $(DESTDIR)$(includedir)
	$(INSTALL) -m 0644 sqlite3.h $(DESTDIR)$(includedir)
	$(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(includedir)
	$(INSTALL) -d $(DESTDIR)$(pkgconfigdir)
	$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(pkgconfigdir)

pkgIndex.tcl:
	echo 'package ifneeded sqlite3 $(RELEASE) [list load $(TCLLIBDIR)/libtclsqlite3.so sqlite3]' > $@
tcl_install:	lib_install libtclsqlite3.la pkgIndex.tcl
	$(INSTALL) -d $(DESTDIR)$(TCLLIBDIR)
	$(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)
	rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a
	$(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR)

clean:	
	rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
	rm -f sqlite3.h opcodes.*
	rm -rf .libs .deps
	rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
	rm -f mkkeywordhash$(BEXE) keywordhash.h







|

|
|
|
|







928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
	$(INSTALL) -d $(DESTDIR)$(includedir)
	$(INSTALL) -m 0644 sqlite3.h $(DESTDIR)$(includedir)
	$(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(includedir)
	$(INSTALL) -d $(DESTDIR)$(pkgconfigdir)
	$(INSTALL) -m 0644 sqlite3.pc $(DESTDIR)$(pkgconfigdir)

pkgIndex.tcl:
	echo 'package ifneeded sqlite3 $(RELEASE) [list load [file join \$dir libtclsqlite3.so] Tclsqlite3]' > $@
tcl_install:	lib_install libtclsqlite3.la pkgIndex.tcl
	$(INSTALL) -d $(DESTDIR)$(TCLLIBDIR)/sqlite3
	$(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/sqlite3
	rm -f $(DESTDIR)$(TCLLIBDIR)/sqlite3/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/sqlite3/libtclsqlite3.a
	$(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR)/sqlite3

clean:	
	rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la
	rm -f sqlite3.h opcodes.*
	rm -rf .libs .deps
	rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
	rm -f mkkeywordhash$(BEXE) keywordhash.h
Changes to src/main.c.
2839
2840
2841
2842
2843
2844
2845








2846
2847
2848
2849
2850
2851
2852
    fd = sqlite3PagerFile(pPager);
    assert( fd!=0 );
    if( op==SQLITE_FCNTL_FILE_POINTER ){
      *(sqlite3_file**)pArg = fd;
      rc = SQLITE_OK;
    }else if( fd->pMethods ){
      rc = sqlite3OsFileControl(fd, op, pArg);








    }else{
      rc = SQLITE_NOTFOUND;
    }
    sqlite3BtreeLeave(pBtree);
  }
  sqlite3_mutex_leave(db->mutex);
  return rc;   







>
>
>
>
>
>
>
>







2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
    fd = sqlite3PagerFile(pPager);
    assert( fd!=0 );
    if( op==SQLITE_FCNTL_FILE_POINTER ){
      *(sqlite3_file**)pArg = fd;
      rc = SQLITE_OK;
    }else if( fd->pMethods ){
      rc = sqlite3OsFileControl(fd, op, pArg);
#ifndef SQLITE_OMIT_WAL
      if( (op==SQLITE_FCNTL_LAST_ERRNO)&&(*(int *)pArg==0) ){
        sqlite3_file *pWalFd = sqlite3PagerWalFile(pPager);
        if( pWalFd&&(pWalFd->pMethods) ){
          rc = sqlite3OsFileControl(pWalFd, op, pArg);
        }
      }
#endif
    }else{
      rc = SQLITE_NOTFOUND;
    }
    sqlite3BtreeLeave(pBtree);
  }
  sqlite3_mutex_leave(db->mutex);
  return rc;   
Changes to src/os_unix.c.
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  unsigned short int ctrlFlags;       /* Behavioral bits.  UNIXFILE_* flags */
  int lastErrno;                      /* The unix errno from last I/O error */
  void *lockingContext;               /* Locking style specific state */
  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() */







|







222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  unsigned short int ctrlFlags;       /* Behavioral bits.  UNIXFILE_* flags */
  int lastErrno;                      /* The unix errno from last I/O error */
  void *lockingContext;               /* Locking style specific state */
  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 || defined(__APPLE__)
  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() */
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
  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;







|







550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
  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 && SQLITE_LOCK_SHARED<eTargetFileLock ){
    rc = pFile->pMethod->xLock(id, SQLITE_LOCK_EXCLUSIVE);
  }
  if( rc ){
    if( pFile->eFileLock > eFileLock ){
      pFile->pMethod->xUnlock(id, eFileLock);
    }
    return rc;
1406
1407
1408
1409
1410
1411
1412




1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
*/
static void robust_close(unixFile *pFile, int h, int lineno){
  if( osClose(h) ){
    unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
                       pFile ? pFile->zPath : 0, lineno);
  }
}





/*
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
*/ 
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







>
>
>
>












|







1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
*/
static void robust_close(unixFile *pFile, int h, int lineno){
  if( osClose(h) ){
    unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close",
                       pFile ? pFile->zPath : 0, lineno);
  }
}

static void storeLastErrno(unixFile *pFile, int error){
  pFile->lastErrno = error;
}

/*
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
*/ 
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) ){
      storeLastErrno(pFile, errno);
      rc = SQLITE_IOERR_CLOSE;
      p->pNext = pError;
      pError = p;
    }else{
      sqlite3_free(p);
    }
#else
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531

  /* Get low-level information about the file that we can used to
  ** create a unique name for the file.
  */
  fd = pFile->h;
  rc = osFstat(fd, &statbuf);
  if( rc!=0 ){
    pFile->lastErrno = errno;
#ifdef EOVERFLOW
    if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
#endif
    return SQLITE_IOERR;
  }

#ifdef __APPLE__
  /* On OS X on an msdos filesystem, the inode number is reported
  ** incorrectly for zero-size files.  See ticket #3260.  To work
  ** around this problem (we consider it a bug in OS X, not SQLite)
  ** we always increase the file size to 1 by writing a single byte
  ** prior to accessing the inode number.  The one byte written is
  ** an ASCII 'S' character which also happens to be the first byte
  ** in the header of every SQLite database.  In this way, if there
  ** is a race condition such that another thread has already populated
  ** the first page of the database, no damage is done.
  */
  if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
    do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR );
    if( rc!=1 ){
      pFile->lastErrno = errno;
      return SQLITE_IOERR;
    }
    rc = osFstat(fd, &statbuf);
    if( rc!=0 ){
      pFile->lastErrno = errno;
      return SQLITE_IOERR;
    }
  }
#endif

  memset(&fileId, 0, sizeof(fileId));
  fileId.dev = statbuf.st_dev;







|




















|




|







1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535

  /* Get low-level information about the file that we can used to
  ** create a unique name for the file.
  */
  fd = pFile->h;
  rc = osFstat(fd, &statbuf);
  if( rc!=0 ){
    storeLastErrno(pFile, errno);
#ifdef EOVERFLOW
    if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS;
#endif
    return SQLITE_IOERR;
  }

#ifdef __APPLE__
  /* On OS X on an msdos filesystem, the inode number is reported
  ** incorrectly for zero-size files.  See ticket #3260.  To work
  ** around this problem (we consider it a bug in OS X, not SQLite)
  ** we always increase the file size to 1 by writing a single byte
  ** prior to accessing the inode number.  The one byte written is
  ** an ASCII 'S' character which also happens to be the first byte
  ** in the header of every SQLite database.  In this way, if there
  ** is a race condition such that another thread has already populated
  ** the first page of the database, no damage is done.
  */
  if( statbuf.st_size==0 && (pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS)!=0 ){
    do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR );
    if( rc!=1 ){
      storeLastErrno(pFile, errno);
      return SQLITE_IOERR;
    }
    rc = osFstat(fd, &statbuf);
    if( rc!=0 ){
      storeLastErrno(pFile, errno);
      return SQLITE_IOERR;
    }
  }
#endif

  memset(&fileId, 0, sizeof(fileId));
  fileId.dev = statbuf.st_dev;
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
    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
  







|


|







1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
    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);
      storeLastErrno(pFile, tErrno);
#else
      rc = SQLITE_IOERR_CHECKRESERVEDLOCK;
      storeLastErrno(pFile, errno);
#endif
    } else if( lock.l_type!=F_UNLCK ){
      reserved = 1;
    }
  }
#endif
  
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
  ){
    lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
    lock.l_start = PENDING_BYTE;
    if( unixFileLock(pFile, &lock, 0) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( IS_LOCK_ERROR(rc) ){
        pFile->lastErrno = tErrno;
      }
      goto end_lock;
    }
  }


  /* If control gets to this point, then actually go ahead and make







|







1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
  ){
    lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
    lock.l_start = PENDING_BYTE;
    if( unixFileLock(pFile, &lock, 0) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( IS_LOCK_ERROR(rc) ){
        storeLastErrno(pFile, tErrno);
      }
      goto end_lock;
    }
  }


  /* If control gets to this point, then actually go ahead and make
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
#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;
    }







|







1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
#else
      rc = SQLITE_IOERR_UNLOCK; 
#endif
    }

    if( rc ){
      if( IS_LOCK_ERROR(rc) ){
        storeLastErrno(pFile, tErrno);
      }
      goto end_lock;
    }else{
      pFile->eFileLock = SHARED_LOCK;
      pInode->nLock++;
      pInode->nShared = 1;
    }
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
      lock.l_len = SHARED_SIZE;
    }

    if( unixFileLock(pFile, &lock, 0) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( rc!=SQLITE_BUSY ){
        pFile->lastErrno = tErrno;
      }
    }
  }
  

#ifndef NDEBUG
  /* Set up the transaction-counter change checking flags when







|







1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
      lock.l_len = SHARED_SIZE;
    }

    if( unixFileLock(pFile, &lock, 0) ){
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( rc!=SQLITE_BUSY ){
        storeLastErrno(pFile, tErrno);
      }
    }
  }
  

#ifndef NDEBUG
  /* Set up the transaction-counter change checking flags when
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
          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;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock(pFile, &lock, 10)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
            pFile->lastErrno = tErrno;
          }
          goto end_unlock;
        }
        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, 10)==(-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;







|















|















|







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
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
            storeLastErrno(pFile, tErrno);
          }
          goto end_unlock;
        }
        lock.l_type = F_RDLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = SHARED_FIRST;
        lock.l_len = divSize;
        if( unixFileLock(pFile, &lock, 10)==(-1) ){
          tErrno = errno;
#if OSLOCKING_CHECK_BUSY_IOERR
          rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK);
#else
          rc = SQLITE_IOERR_UNLOCK;
#endif
          if( IS_LOCK_ERROR(rc) ){
            storeLastErrno(pFile, tErrno);
          }
          goto end_unlock;
        }
        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, 10)==(-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) ){
            storeLastErrno(pFile, tErrno);
          }
          goto end_unlock;
        }
      }else
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
      {
        lock.l_type = F_RDLCK;
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
          /* 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 = tErrno;
#endif
          if( IS_LOCK_ERROR(rc) ){
            pFile->lastErrno = tErrno;
          }
          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, 10)==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







|


|
















|



|







2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
          /* 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;
          storeLastErrno(pFile, tErrno);
#endif
          if( IS_LOCK_ERROR(rc) ){
            storeLastErrno(pFile, tErrno);
          }
          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, 10)==0 ){
      pInode->eFileLock = SHARED_LOCK;
    }else{
#if OSLOCKING_CHECK_BUSY_IOERR
      tErrno = errno;
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
      if( IS_LOCK_ERROR(rc) ){
        storeLastErrno(pFile, tErrno);
      }
#else
      rc = SQLITE_IOERR_UNLOCK;
      storeLastErrno(pFile, 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
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
      if( unixFileLock(pFile, &lock, 10)==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







|



|







2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
      if( unixFileLock(pFile, &lock, 10)==0 ){
        pInode->eFileLock = NO_LOCK;
      }else{
#if OSLOCKING_CHECK_BUSY_IOERR
        tErrno = errno;
        rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
        if( IS_LOCK_ERROR(rc) ){
          storeLastErrno(pFile, tErrno);
        }
#else
        rc = SQLITE_IOERR_UNLOCK;
	    storeLastErrno(pFile, errno);
#endif
        pInode->eFileLock = NO_LOCK;
        pFile->eFileLock = NO_LOCK;
      }
    }

    /* Decrement the count of locks against this same file.  When the
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
*/
static int closeUnixFile(sqlite3_file *id){
  unixFile *pFile = (unixFile*)id;
#if OSCLOSE_CHECK_CLOSE_IOERR
  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->h>=0 ){







|







2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
*/
static int closeUnixFile(sqlite3_file *id){
  unixFile *pFile = (unixFile*)id;
#if OSCLOSE_CHECK_CLOSE_IOERR
  if( pFile->h>=0 ){
    int err = close(pFile->h);
    if( err ){
      storeLastErrno(pFile, errno);
      return SQLITE_IOERR_CLOSE;
    }else{
      pFile->h=-1;
    }
  }
#else
  if( pFile->h>=0 ){
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
    /* failed to open/create the lock directory */
    int tErrno = errno;
    if( EEXIST == tErrno ){
      rc = SQLITE_BUSY;
    } else {
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( IS_LOCK_ERROR(rc) ){
        pFile->lastErrno = tErrno;
      }
    }
    return rc;
  } 
  
  /* got it, set the type and return ok */
  pFile->eFileLock = eFileLock;







|







2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
    /* failed to open/create the lock directory */
    int tErrno = errno;
    if( EEXIST == tErrno ){
      rc = SQLITE_BUSY;
    } else {
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
      if( IS_LOCK_ERROR(rc) ){
        storeLastErrno(pFile, tErrno);
      }
    }
    return rc;
  } 
  
  /* got it, set the type and return ok */
  pFile->eFileLock = eFileLock;
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
#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;
  return SQLITE_OK;
}








|







2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
#if OSLOCKING_CHECK_BUSY_IOERR
      rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
#else
      rc = SQLITE_IOERR_UNLOCK;
#endif
    }
    if( IS_LOCK_ERROR(rc) ){
      storeLastErrno(pFile, tErrno);
    }
    return rc; 
  }
  pFile->eFileLock = NO_LOCK;
  return SQLITE_OK;
}

2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
        /* 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;
      reserved = 1;
      /* someone else might have it reserved */
      lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); 
      if( IS_LOCK_ERROR(lrc) ){
        pFile->lastErrno = tErrno;
        rc = lrc;
      }
    }
  }
  OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));

#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS







|









|







2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
        /* 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) ){
          storeLastErrno(pFile, tErrno);
          rc = lrc;
        }
      }
    } else {
      int tErrno = errno;
      reserved = 1;
      /* someone else might have it reserved */
      lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); 
      if( IS_LOCK_ERROR(lrc) ){
        storeLastErrno(pFile, tErrno);
        rc = lrc;
      }
    }
  }
  OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));

#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
  /* grab an exclusive lock */
  
  if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
    int tErrno = errno;
    /* didn't get, must be busy */
    rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
    if( IS_LOCK_ERROR(rc) ){
      pFile->lastErrno = tErrno;
    }
  } else {
    /* got it, set the type and return ok */
    pFile->eFileLock = eFileLock;
  }
  OSTRACE(("LOCK    %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock), 
           rc==SQLITE_OK ? "ok" : "failed"));







|







2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
  /* grab an exclusive lock */
  
  if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
    int tErrno = errno;
    /* didn't get, must be busy */
    rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
    if( IS_LOCK_ERROR(rc) ){
      storeLastErrno(pFile, tErrno);
    }
  } else {
    /* got it, set the type and return ok */
    pFile->eFileLock = eFileLock;
  }
  OSTRACE(("LOCK    %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock), 
           rc==SQLITE_OK ? "ok" : "failed"));
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
    sem_t *pSem = pFile->pInode->pSem;
    struct stat statBuf;

    if( sem_trywait(pSem)==-1 ){
      int tErrno = errno;
      if( EAGAIN != tErrno ){
        rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
        pFile->lastErrno = tErrno;
      } else {
        /* someone else has the lock when we are in NO_LOCK */
        reserved = (pFile->eFileLock < SHARED_LOCK);
      }
    }else{
      /* we could have it if we want it */
      sem_post(pSem);







|







2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
    sem_t *pSem = pFile->pInode->pSem;
    struct stat statBuf;

    if( sem_trywait(pSem)==-1 ){
      int tErrno = errno;
      if( EAGAIN != tErrno ){
        rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_CHECKRESERVEDLOCK);
        storeLastErrno(pFile, tErrno);
      } else {
        /* someone else has the lock when we are in NO_LOCK */
        reserved = (pFile->eFileLock < SHARED_LOCK);
      }
    }else{
      /* we could have it if we want it */
      sem_post(pSem);
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
  }
  
  /* no, really unlock. */
  if ( sem_post(pSem)==-1 ) {
    int rc, tErrno = errno;
    rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
    if( IS_LOCK_ERROR(rc) ){
      pFile->lastErrno = tErrno;
    }
    return rc; 
  }
  pFile->eFileLock = NO_LOCK;
  return SQLITE_OK;
}








|







2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
  }
  
  /* no, really unlock. */
  if ( sem_post(pSem)==-1 ) {
    int rc, tErrno = errno;
    rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK);
    if( IS_LOCK_ERROR(rc) ){
      storeLastErrno(pFile, tErrno);
    }
    return rc; 
  }
  pFile->eFileLock = NO_LOCK;
  return SQLITE_OK;
}

2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
    rc = SQLITE_BUSY;
#else
    rc = sqliteErrorFromPosixError(tErrno,
                    setLockFlag ? SQLITE_IOERR_LOCK : SQLITE_IOERR_UNLOCK);
#endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */
    if( IS_LOCK_ERROR(rc) ){
      pFile->lastErrno = tErrno;
    }
    return rc;
  } else {
    return SQLITE_OK;
  }
}








|







2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
    rc = SQLITE_BUSY;
#else
    rc = sqliteErrorFromPosixError(tErrno,
                    setLockFlag ? SQLITE_IOERR_LOCK : SQLITE_IOERR_UNLOCK);
#endif /* SQLITE_IGNORE_AFP_LOCK_ERRORS */
    if( IS_LOCK_ERROR(rc) ){
      storeLastErrno(pFile, tErrno);
    }
    return rc;
  } else {
    return SQLITE_OK;
  }
}

3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
    if( IS_LOCK_ERROR(lrc1) ){
      lrc1Errno = pFile->lastErrno;
    }
    /* Drop the temporary PENDING lock */
    lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
    
    if( IS_LOCK_ERROR(lrc1) ) {
      pFile->lastErrno = lrc1Errno;
      rc = lrc1;
      goto afp_end_lock;
    } else if( IS_LOCK_ERROR(lrc2) ){
      rc = lrc2;
      goto afp_end_lock;
    } else if( lrc1 != SQLITE_OK ) {
      rc = lrc1;







|







3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
    if( IS_LOCK_ERROR(lrc1) ){
      lrc1Errno = pFile->lastErrno;
    }
    /* Drop the temporary PENDING lock */
    lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
    
    if( IS_LOCK_ERROR(lrc1) ) {
      storeLastErrno(pFile, lrc1Errno);
      rc = lrc1;
      goto afp_end_lock;
    } else if( IS_LOCK_ERROR(lrc2) ){
      rc = lrc2;
      goto afp_end_lock;
    } else if( lrc1 != SQLITE_OK ) {
      rc = lrc1;
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
    got = osPread64(id->h, pBuf, cnt, offset);
    SimulateIOError( got = -1 );
#else
    newOffset = lseek(id->h, offset, SEEK_SET);
    SimulateIOError( newOffset-- );
    if( newOffset!=offset ){
      if( newOffset == -1 ){
        ((unixFile*)id)->lastErrno = errno;
      }else{
        ((unixFile*)id)->lastErrno = 0;			
      }
      return -1;
    }
    got = osRead(id->h, pBuf, cnt);
#endif
    if( got==cnt ) break;
    if( got<0 ){
      if( errno==EINTR ){ got = 1; continue; }
      prior = 0;
      ((unixFile*)id)->lastErrno = errno;
      break;
    }else if( got>0 ){
      cnt -= got;
      offset += got;
      prior += got;
      pBuf = (void*)(got + (char*)pBuf);
    }







|

|









|







3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
    got = osPread64(id->h, pBuf, cnt, offset);
    SimulateIOError( got = -1 );
#else
    newOffset = lseek(id->h, offset, SEEK_SET);
    SimulateIOError( newOffset-- );
    if( newOffset!=offset ){
      if( newOffset == -1 ){
        storeLastErrno((unixFile*)id, errno);
      }else{
        storeLastErrno((unixFile*)id, 0);
      }
      return -1;
    }
    got = osRead(id->h, pBuf, cnt);
#endif
    if( got==cnt ) break;
    if( got<0 ){
      if( errno==EINTR ){ got = 1; continue; }
      prior = 0;
      storeLastErrno((unixFile*)id, errno);
      break;
    }else if( got>0 ){
      cnt -= got;
      offset += got;
      prior += got;
      pBuf = (void*)(got + (char*)pBuf);
    }
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
  got = seekAndRead(pFile, offset, pBuf, amt);
  if( got==amt ){
    return SQLITE_OK;
  }else if( got<0 ){
    /* lastErrno set by seekAndRead */
    return SQLITE_IOERR_READ;
  }else{
    pFile->lastErrno = 0; /* not a system error */
    /* Unread parts of the buffer must be zero-filled */
    memset(&((char*)pBuf)[got], 0, amt-got);
    return SQLITE_IOERR_SHORT_READ;
  }
}

/*







|







3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
  got = seekAndRead(pFile, offset, pBuf, amt);
  if( got==amt ){
    return SQLITE_OK;
  }else if( got<0 ){
    /* lastErrno set by seekAndRead */
    return SQLITE_IOERR_READ;
  }else{
    //storeLastErrno(pFile, 0); /* not a system error, but we want to preserve lastErrno */
    /* Unread parts of the buffer must be zero-filled */
    memset(&((char*)pBuf)[got], 0, amt-got);
    return SQLITE_IOERR_SHORT_READ;
  }
}

/*
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
  do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR);
#else
  do{
    newOffset = lseek(id->h, offset, SEEK_SET);
    SimulateIOError( newOffset-- );
    if( newOffset!=offset ){
      if( newOffset == -1 ){
        ((unixFile*)id)->lastErrno = errno;
      }else{
        ((unixFile*)id)->lastErrno = 0;			
      }
      return -1;
    }
    got = osWrite(id->h, pBuf, cnt);
  }while( got<0 && errno==EINTR );
#endif
  TIMER_END;
  if( got<0 ){
    ((unixFile*)id)->lastErrno = errno;
  }

  OSTRACE(("WRITE   %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
  return got;
}









|

|








|







3494
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
  do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR);
#else
  do{
    newOffset = lseek(id->h, offset, SEEK_SET);
    SimulateIOError( newOffset-- );
    if( newOffset!=offset ){
      if( newOffset == -1 ){
        storeLastErrno((unixFile*)id, errno);
      }else{
        storeLastErrno((unixFile*)id, 0);
      }
      return -1;
    }
    got = osWrite(id->h, pBuf, cnt);
  }while( got<0 && errno==EINTR );
#endif
  TIMER_END;
  if( got<0 ){
    storeLastErrno((unixFile*)id, errno);
  }

  OSTRACE(("WRITE   %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
  return got;
}


3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
  SimulateDiskfullError(( wrote=0, amt=1 ));

  if( amt>0 ){
    if( wrote<0 && pFile->lastErrno!=ENOSPC ){
      /* lastErrno set by seekAndWrite */
      return SQLITE_IOERR_WRITE;
    }else{
      pFile->lastErrno = 0; /* not a system error */
      return SQLITE_FULL;
    }
  }

  return SQLITE_OK;
}








|







3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
  SimulateDiskfullError(( wrote=0, amt=1 ));

  if( amt>0 ){
    if( wrote<0 && pFile->lastErrno!=ENOSPC ){
      /* lastErrno set by seekAndWrite */
      return SQLITE_IOERR_WRITE;
    }else{
      //storeLastErrno(pFile, 0); /* not a system error, but we want to preserve lastErrno */
      return SQLITE_FULL;
    }
  }

  return SQLITE_OK;
}

3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
  SimulateDiskfullError( return SQLITE_FULL );

  assert( pFile );
  OSTRACE(("SYNC    %-3d\n", pFile->h));
  rc = full_fsync(pFile->h, isFullsync, isDataOnly);
  SimulateIOError( rc=1 );
  if( rc ){
    pFile->lastErrno = errno;
    return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
  }

  /* Also fsync the directory containing the file if the DIRSYNC flag
  ** is set.  This is a one-time occurrance.  Many systems (examples: AIX)
  ** are unable to fsync a directory, so ignore errors on the fsync.
  */
  if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){
    int dirfd;
    OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath,
            HAVE_FULLFSYNC, isFullsync));
    rc = osOpenDirectory(pFile->zPath, &dirfd);
    if( rc==SQLITE_OK && dirfd>=0 ){
      full_fsync(dirfd, 0, 0);
#if OSCLOSE_CHECK_CLOSE_IOERR
      if( close(pFile->dirfd) ){
        pFile->lastErrno = errno;
        rc = SQLITE_IOERR_DIR_CLOSE;
      }
#else
      robust_close(pFile, dirfd, __LINE__);
#endif
    }else if( rc==SQLITE_CANTOPEN ){
      rc = SQLITE_OK;







|
















|







3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
  SimulateDiskfullError( return SQLITE_FULL );

  assert( pFile );
  OSTRACE(("SYNC    %-3d\n", pFile->h));
  rc = full_fsync(pFile->h, isFullsync, isDataOnly);
  SimulateIOError( rc=1 );
  if( rc ){
    storeLastErrno(pFile, errno);
    return unixLogError(SQLITE_IOERR_FSYNC, "full_fsync", pFile->zPath);
  }

  /* Also fsync the directory containing the file if the DIRSYNC flag
  ** is set.  This is a one-time occurrance.  Many systems (examples: AIX)
  ** are unable to fsync a directory, so ignore errors on the fsync.
  */
  if( pFile->ctrlFlags & UNIXFILE_DIRSYNC ){
    int dirfd;
    OSTRACE(("DIRSYNC %s (have_fullfsync=%d fullsync=%d)\n", pFile->zPath,
            HAVE_FULLFSYNC, isFullsync));
    rc = osOpenDirectory(pFile->zPath, &dirfd);
    if( rc==SQLITE_OK && dirfd>=0 ){
      full_fsync(dirfd, 0, 0);
#if OSCLOSE_CHECK_CLOSE_IOERR
      if( close(pFile->dirfd) ){
        storeLastErrno(pFile, errno);
        rc = SQLITE_IOERR_DIR_CLOSE;
      }
#else
      robust_close(pFile, dirfd, __LINE__);
#endif
    }else if( rc==SQLITE_CANTOPEN ){
      rc = SQLITE_OK;
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
  */
  if( pFile->szChunk>0 ){
    nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
  }

  rc = robust_ftruncate(pFile->h, (off_t)nByte);
  if( rc ){
    pFile->lastErrno = errno;
    return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
  }else{
#ifndef NDEBUG
    /* If we are doing a normal write to a database file (as opposed to
    ** doing a hot-journal rollback or a write to some file other than a
    ** normal database file) and we truncate the file to zero length,
    ** that effectively updates the change counter.  This might happen







|







3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
  */
  if( pFile->szChunk>0 ){
    nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
  }

  rc = robust_ftruncate(pFile->h, (off_t)nByte);
  if( rc ){
    storeLastErrno(pFile, errno);
    return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
  }else{
#ifndef NDEBUG
    /* If we are doing a normal write to a database file (as opposed to
    ** doing a hot-journal rollback or a write to some file other than a
    ** normal database file) and we truncate the file to zero length,
    ** that effectively updates the change counter.  This might happen
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
static int unixFileSize(sqlite3_file *id, i64 *pSize){
  int rc;
  struct stat buf;
  assert( id );
  rc = osFstat(((unixFile*)id)->h, &buf);
  SimulateIOError( rc=1 );
  if( rc!=0 ){
    ((unixFile*)id)->lastErrno = errno;
    return SQLITE_IOERR_FSTAT;
  }
  *pSize = buf.st_size;

  /* When opening a zero-size database, the findInodeInfo() procedure
  ** writes a single byte into that file in order to work around a bug
  ** in the OS-X msdos filesystem.  In order to avoid problems with upper







|







3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
static int unixFileSize(sqlite3_file *id, i64 *pSize){
  int rc;
  struct stat buf;
  assert( id );
  rc = osFstat(((unixFile*)id)->h, &buf);
  SimulateIOError( rc=1 );
  if( rc!=0 ){
    storeLastErrno((unixFile*)id, errno);
    return SQLITE_IOERR_FSTAT;
  }
  *pSize = buf.st_size;

  /* When opening a zero-size database, the findInodeInfo() procedure
  ** writes a single byte into that file in order to work around a bug
  ** in the OS-X msdos filesystem.  In order to avoid problems with upper
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
      ** is the same technique used by glibc to implement posix_fallocate()
      ** on systems that do not have a real fallocate() system call.
      */
      int nBlk = buf.st_blksize;  /* File-system block size */
      i64 iWrite;                 /* Next offset to write to */

      if( robust_ftruncate(pFile->h, nSize) ){
        pFile->lastErrno = errno;
        return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
      }
      iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
      while( iWrite<nSize ){
        int nWrite = seekAndWrite(pFile, iWrite, "", 1);
        if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
        iWrite += nBlk;







|







3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
      ** is the same technique used by glibc to implement posix_fallocate()
      ** on systems that do not have a real fallocate() system call.
      */
      int nBlk = buf.st_blksize;  /* File-system block size */
      i64 iWrite;                 /* Next offset to write to */

      if( robust_ftruncate(pFile->h, nSize) ){
        storeLastErrno(pFile, errno);
        return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
      }
      iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
      while( iWrite<nSize ){
        int nWrite = seekAndWrite(pFile, iWrite, "", 1);
        if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
        iWrite += nBlk;
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033



4034
4035
4036
4037
4038
4039
4040
    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;
      }







|





>
>
>







4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
    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;
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
      if ((pSrcFile->openFlags & O_RDWR) == O_RDWR) {
        srcFlags = SQLITE_OPEN_READWRITE;
      } else {
        srcFlags = SQLITE_OPEN_READONLY;
      }
#else
      srcFlags = SQLITE_OPEN_READWRITE;
#endif
#if SQLITE_ENABLE_DATA_PROTECTION
      srcFlags |= pSrcFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
      if( isProxyLockingMode(pSrcFile) ){
        srcFlags |= SQLITE_OPEN_AUTOPROXY;
      }
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
      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);







|







4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
      if( fcopyfile(srcWalFD, dstWalFD, s, COPYFILE_ALL) ){
        int err=errno;
        switch(err) {
          case ENOMEM:
            rc = SQLITE_NOMEM;
            break;
          default:
            storeLastErrno(pFile, err);
            rc = SQLITE_IOERR;
        }
      }
      copyfile_state_free(s);
      close(dstWalFD);
    }
    close(srcWalFD);
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
    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 */







|







4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
    if( fcopyfile(pSrcFile->h, pFile->h, s, COPYFILE_ALL) ){
      int err=errno;
      switch(err) {
        case ENOMEM:
          rc = SQLITE_NOMEM;
          break;
        default:
          storeLastErrno(pFile, err);
          rc = SQLITE_IOERR;
      }
    }
    copyfile_state_free(s);
    
    if (srcChange == dstChange) {
      /* modify the change counter to force page zero to be reloaded */
4620
4621
4622
4623
4624
4625
4626
4627





4628
4629
4630
4631
4632
4633
4634
    if( pShmNode->mutex==0 ){
      rc = SQLITE_NOMEM;
      goto shm_open_err;
    }

    if( pInode->bProcessLock==0 ){
      int openFlags = O_RDWR | O_CREAT;
      if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){





        openFlags = O_RDONLY;
        pShmNode->isReadonly = 1;
      }
      pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
      if( pShmNode->h<0 ){
        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
        goto shm_open_err;







|
>
>
>
>
>







4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
    if( pShmNode->mutex==0 ){
      rc = SQLITE_NOMEM;
      goto shm_open_err;
    }

    if( pInode->bProcessLock==0 ){
      int openFlags = O_RDWR | O_CREAT;
      if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0)
#if defined(SQLITE_ENABLE_PERSIST_WAL)&&(SQLITE_ENABLE_LOCKING_STYLE \
    || defined(__APPLE__))
         || (pDbFd->openFlags & O_RDWR) != O_RDWR
#endif
         ){
        openFlags = O_RDONLY;
        pShmNode->isReadonly = 1;
      }
      pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
      if( pShmNode->h<0 ){
        rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
        goto shm_open_err;
5069
5070
5071
5072
5073
5074
5075
5076









































































5077
5078
5079
5080
5081
5082
5083

5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116




5117
5118
5119
5120
5121
5122
5123
          close(jfd);
        }
      }
    }
  }
  return SQLITE_OK;
}










































































static int unixTruncateDatabase(unixFile *pFile, int bFlags) {
  sqlite3_file *id = (sqlite3_file *)pFile;
  int rc = SQLITE_OK;
  void *pLock = NULL;
  int flags = 0;
  int corruptFileLock = 0;
  int isCorrupt = 0;

    
#if SQLITE_ENABLE_DATA_PROTECTION
  flags |= pFile->protFlags;
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
  if( isProxyLockingMode(pFile) ){
    flags |= SQLITE_OPEN_AUTOPROXY;
  }
#endif
  
  rc = sqlite3demo_superlock(pFile->zPath, 0, flags, 0, 0, &pLock);
  if( rc ){
    if( rc==SQLITE_CORRUPT || rc==SQLITE_NOTADB ){
      isCorrupt = 1;
      rc = sqlite3demo_superlock_corrupt(id, SQLITE_LOCK_EXCLUSIVE, &corruptFileLock);
    }
    if( rc ){
      return rc;
    }
  }
  if( bFlags!=0 ){
    /* initialize a new database in TMPDIR and copy the contents over */
    const char *tDir = unixTempFileDir();
    int tLen = sizeof(char) * (strlen(tDir) + 11);
    char *tDbPath = (char *)malloc(tLen);
    int tFd = -1;
    
    strlcpy(tDbPath, tDir, tLen);
    strlcat(tDbPath, "tmpdbXXXXX", tLen);
    tFd = mkstemp(tDbPath);
    if( tFd==-1 ){
      pFile->lastErrno=errno;
      rc = SQLITE_IOERR;




    }else{
      sqlite3 *tDb = NULL;
      copyfile_state_t s;
      int trc = sqlite3_open_v2(tDbPath, &tDb, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_AUTOPROXY, NULL);
      char *errmsg = NULL;
      const char *sql = "";
      if( !trc && (bFlags&SQLITE_TRUNCATE_PAGESIZE_MASK) ){








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







>
|















|



|










|

>
>
>
>







5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
          close(jfd);
        }
      }
    }
  }
  return SQLITE_OK;
}

static int unixUnsafeTruncateDatabase(unixFile *pFile){
  // this is nasty & bad.  destruction with prejudice.  we'll lose all the file locks in this process, however.
  // sqlite3_file_control works properly.  But if it fails, this works approximately
  char journalPath[MAXPATHLEN];
  char walPath[MAXPATHLEN];
  int rc = SQLITE_OK;
  
  strlcpy(journalPath, pFile->zPath, MAXPATHLEN);
  strlcat(journalPath, "-journal", MAXPATHLEN);
  strlcpy(walPath, pFile->zPath, MAXPATHLEN);
  strlcat(walPath, "-wal", MAXPATHLEN);
  int fd1 = pFile->h;
  int result = 0;
  result = ftruncate(fd1, 0ll);
  if (result) {
    result = errno;
  }
  if (result) {
    rc = SQLITE_IOERR;
    storeLastErrno(pFile, result);
  }
  
  int fd2 = open(journalPath, O_RDWR);
  int result2 = 0;
  if (fd2 < 0) {
    if (errno != ENOENT) {
      result2 = errno;
    } else {
      result2 = 0;
    }
  } else {
    result2 = ftruncate(fd2, 0ll);
    if (result2) {
      result2 = errno;
    }
  }
  if (result2 && !result) {
    rc = SQLITE_IOERR;
    storeLastErrno(pFile, result2);
  }
  
  int fd3 = open(walPath, O_RDWR);
  int result3 = 0;
  if (fd3 < 0) {
    if (errno != ENOENT) {
      result3 = errno;
    } else {
      result3 = 0;
    }
  } else {
    result3 = ftruncate(fd3, 0ll);
    if (result3) {
      result3 = errno;
    }
  }
  if (result3 && !(result || result2)) {
    rc = SQLITE_IOERR;
    storeLastErrno(pFile, result2);
  }
  
  if (fd3 >= 0) {
    fsync(fd3);
    close(fd3);
  }
  if (fd2 >= 0) {
    fsync(fd2);
    close(fd2);
  }
  fsync(fd1);
	
  return rc;
}

static int unixTruncateDatabase(unixFile *pFile, int bFlags) {
  sqlite3_file *id = (sqlite3_file *)pFile;
  int rc = SQLITE_OK;
  void *pLock = NULL;
  int flags = 0;
  int corruptFileLock = 0;
  int isCorrupt = 0;
  int force = (bFlags & SQLITE_TRUNCATE_FORCE);
  
#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 && !force ){
      return rc;
    }
  }
  if( (bFlags&SQLITE_TRUNCATE_INITIALIZE_HEADER_MASK)!=0 ){
    /* initialize a new database in TMPDIR and copy the contents over */
    const char *tDir = unixTempFileDir();
    int tLen = sizeof(char) * (strlen(tDir) + 11);
    char *tDbPath = (char *)malloc(tLen);
    int tFd = -1;
    
    strlcpy(tDbPath, tDir, tLen);
    strlcat(tDbPath, "tmpdbXXXXX", tLen);
    tFd = mkstemp(tDbPath);
    if( tFd==-1 ){
      storeLastErrno(pFile, errno);
      rc = SQLITE_IOERR;
      if( force ){
        /* attempt the truncation, even if we can't seed the database in a temp directory */
        rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
      }
    }else{
      sqlite3 *tDb = NULL;
      copyfile_state_t s;
      int trc = sqlite3_open_v2(tDbPath, &tDb, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_AUTOPROXY, NULL);
      char *errmsg = NULL;
      const char *sql = "";
      if( !trc && (bFlags&SQLITE_TRUNCATE_PAGESIZE_MASK) ){
5145
5146
5147
5148
5149
5150
5151



5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186


5187





5188
5189
5190
5191
5192
5193
5194
        if( !tDb ){
          fprintf(stderr, "failed to open temp database '%s' to reset truncated database %s with flags %x: %d\n", tDbPath, pFile->zPath, bFlags, trc);
        }else{
          fprintf(stderr, "failed to set '%s' on truncated database %s, %d: %s\n", sql, pFile->zPath, trc, errmsg);
        }
      }
      if( tDb ){



        sqlite3_close(tDb);
      }
      s = copyfile_state_alloc();
      lseek(tFd, 0, SEEK_SET);
      lseek(pFile->h, 0, SEEK_SET);
      if( fcopyfile(tFd, 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);
      fsync(pFile->h);
      close(tFd);
      unlink(tDbPath);
    }
    free(tDbPath);
  } else {
    rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
  }
  if( rc==SQLITE_OK ){
    unixInvalidateSupportFiles(pFile, 0);
  }
  pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);


  if( isCorrupt ){
    sqlite3demo_superunlock_corrupt(id, corruptFileLock);
  }else{
    sqlite3demo_superunlock(pLock);


  }





  return rc;
}

/*
 ** Lock locations for shared-memory locks used by WAL mode.
 */
#ifndef SHM_BASE







>
>
>












|












|







|

>
>

>
>
>
>
>







5235
5236
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
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
        if( !tDb ){
          fprintf(stderr, "failed to open temp database '%s' to reset truncated database %s with flags %x: %d\n", tDbPath, pFile->zPath, bFlags, trc);
        }else{
          fprintf(stderr, "failed to set '%s' on truncated database %s, %d: %s\n", sql, pFile->zPath, trc, errmsg);
        }
      }
      if( tDb ){
        int off = 0;
        /* merge the wal into the db */
        sqlite3_file_control(tDb, NULL, SQLITE_FCNTL_PERSIST_WAL, &off);
        sqlite3_close(tDb);
      }
      s = copyfile_state_alloc();
      lseek(tFd, 0, SEEK_SET);
      lseek(pFile->h, 0, SEEK_SET);
      if( fcopyfile(tFd, pFile->h, s, COPYFILE_ALL) ){
        int err=errno;
        switch(err) {
          case ENOMEM:
            rc = SQLITE_NOMEM;
            break;
          default:
            storeLastErrno(pFile, err);
            rc = SQLITE_IOERR;
        }
      }
      copyfile_state_free(s);
      fsync(pFile->h);
      close(tFd);
      unlink(tDbPath);
    }
    free(tDbPath);
  } else {
    rc = pFile->pMethod->xTruncate(id, ((pFile->fsFlags & SQLITE_FSFLAGS_IS_MSDOS) != 0) ? 1L : 0L);
  }
  if( rc==SQLITE_OK || force ){
    unixInvalidateSupportFiles(pFile, 0);
  }
  pFile->pMethod->xSync(id, SQLITE_SYNC_FULL);


  if( isCorrupt ){
    sqlite3demo_superunlock_corrupt(id, corruptFileLock);
  }else if( pLock ){
    sqlite3demo_superunlock(pLock);
  }else{
    assert(force);
  }
  
  if( rc!=SQLITE_OK && force){
    unixUnsafeTruncateDatabase(pFile);
  }
  
  return rc;
}

/*
 ** Lock locations for shared-memory locks used by WAL mode.
 */
#ifndef SHM_BASE
5204
5205
5206
5207
5208
5209
5210
5211
5212

5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228


5229
5230
5231
5232
5233
5234
5235

5236

5237
5238
5239
5240
5241
5242
5243
** This test only works for lock testing on unix/posix VFS.
** Adapted from tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
*/
static int unixLockstatePid(unixFile *pFile, pid_t pid, int *pLockstate){
  int hDb;        /* File descriptor for the open database file */
  int hShm = -1;  /* File descriptor for WAL shared-memory file */
  ssize_t got;    /* Bytes read from header */
  int isWal;                 /* True if in WAL mode */
  int nLock = 0;             /* Number of locks held */

  unsigned char aHdr[100];   /* Database header */
  
  assert(pLockstate);
  
  /* make sure we are dealing with a database file */
  hDb = pFile->h;
  if( hDb<0 ){
    *pLockstate = SQLITE_LOCKSTATE_ERROR;
    return SQLITE_ERROR;
  }
  assert( (strlen(SQLITE_FILE_HEADER)+1)==SQLITE_FILE_HEADER_LEN );
  got = pread(hDb, aHdr, 100, 0);
  if( got<0 ){
    *pLockstate = SQLITE_LOCKSTATE_ERROR;
    return SQLITE_ERROR;
  }


  if( got!=100 || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0 ){
    *pLockstate = SQLITE_LOCKSTATE_NOTADB;
    return SQLITE_NOTADB;
  }
  
  /* First check for an exclusive lock */
  nLock += unixIsLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE");

  isWal = aHdr[18]==2;

  if( nLock==0 && isWal==0 ){
    /* Rollback mode */
    nLock += unixIsLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2, "PENDING|RESERVED|SHARED");
  }
  if( nLock==0 && isWal!=0 ){
    /* lookup the file descriptor for the shared memory file if we have it open in this process */
    unixEnterMutex(); /* Because pFile->pInode is shared across threads */







|

>
















>
>
|






>
|
>







5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
** This test only works for lock testing on unix/posix VFS.
** Adapted from tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
*/
static int unixLockstatePid(unixFile *pFile, pid_t pid, int *pLockstate){
  int hDb;        /* File descriptor for the open database file */
  int hShm = -1;  /* File descriptor for WAL shared-memory file */
  ssize_t got;    /* Bytes read from header */
  int isWal = 0;             /* True if in WAL mode */
  int nLock = 0;             /* Number of locks held */
  int noHdr = 0;             /* Zero byte DB has no header */
  unsigned char aHdr[100];   /* Database header */
  
  assert(pLockstate);
  
  /* make sure we are dealing with a database file */
  hDb = pFile->h;
  if( hDb<0 ){
    *pLockstate = SQLITE_LOCKSTATE_ERROR;
    return SQLITE_ERROR;
  }
  assert( (strlen(SQLITE_FILE_HEADER)+1)==SQLITE_FILE_HEADER_LEN );
  got = pread(hDb, aHdr, 100, 0);
  if( got<0 ){
    *pLockstate = SQLITE_LOCKSTATE_ERROR;
    return SQLITE_ERROR;
  }
  if( got==0 ){
    noHdr = 1;
  }else if( got!=100 || memcmp(aHdr, SQLITE_FILE_HEADER, SQLITE_FILE_HEADER_LEN)!=0 ){
    *pLockstate = SQLITE_LOCKSTATE_NOTADB;
    return SQLITE_NOTADB;
  }
  
  /* First check for an exclusive lock */
  nLock += unixIsLocked(pid, hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE");
  if (!noHdr) {
    isWal = aHdr[18]==2;
  }
  if( nLock==0 && isWal==0 ){
    /* Rollback mode */
    nLock += unixIsLocked(pid, hDb, F_WRLCK, PENDING_BYTE, SHARED_SIZE+2, "PENDING|RESERVED|SHARED");
  }
  if( nLock==0 && isWal!=0 ){
    /* lookup the file descriptor for the shared memory file if we have it open in this process */
    unixEnterMutex(); /* Because pFile->pInode is shared across threads */
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
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
  if( isDelete ){
#if OS_VXWORKS
    zPath = zName;
#else
    osUnlink(zName);
#endif
  }
#if SQLITE_ENABLE_LOCKING_STYLE
  else{
    p->openFlags = openFlags;
  }
#endif

  noLock = eType!=SQLITE_OPEN_MAIN_DB;

  
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
  if( fstatfs(fd, &fsInfo) == -1 ){
    ((unixFile*)pFile)->lastErrno = errno;
    robust_close(p, fd, __LINE__);
    return SQLITE_IOERR_ACCESS;
  }
  if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
    ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
  }
  if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) {
    ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
  }
#endif

  /* Set up appropriate ctrlFlags */
  if( isDelete )                ctrlFlags |= UNIXFILE_DELETE;
  if( isReadonly )              ctrlFlags |= UNIXFILE_RDONLY;
  if( noLock )                  ctrlFlags |= UNIXFILE_NOLOCK;
  if( syncDir )                 ctrlFlags |= UNIXFILE_DIRSYNC;
  if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;






#if SQLITE_ENABLE_LOCKING_STYLE
#if SQLITE_PREFER_PROXY_LOCKING
  isAutoProxy = 1;
#endif
  if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){
    char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");







|










|

















>
>
>
>
>







6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
  if( isDelete ){
#if OS_VXWORKS
    zPath = zName;
#else
    osUnlink(zName);
#endif
  }
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
  else{
    p->openFlags = openFlags;
  }
#endif

  noLock = eType!=SQLITE_OPEN_MAIN_DB;

  
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
  if( fstatfs(fd, &fsInfo) == -1 ){
    storeLastErrno(p, errno);
    robust_close(p, fd, __LINE__);
    return SQLITE_IOERR_ACCESS;
  }
  if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) {
    ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
  }
  if (0 == strncmp("exfat", fsInfo.f_fstypename, 5)) {
    ((unixFile*)pFile)->fsFlags |= SQLITE_FSFLAGS_IS_MSDOS;
  }
#endif

  /* Set up appropriate ctrlFlags */
  if( isDelete )                ctrlFlags |= UNIXFILE_DELETE;
  if( isReadonly )              ctrlFlags |= UNIXFILE_RDONLY;
  if( noLock )                  ctrlFlags |= UNIXFILE_NOLOCK;
  if( syncDir )                 ctrlFlags |= UNIXFILE_DIRSYNC;
  if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
#if defined(SQLITE_ENABLE_PERSIST_WAL)
  if( eType==SQLITE_OPEN_MAIN_DB ) {
    ctrlFlags |= UNIXFILE_PERSIST_WAL;
  }
#endif

#if SQLITE_ENABLE_LOCKING_STYLE
#if SQLITE_PREFER_PROXY_LOCKING
  isAutoProxy = 1;
#endif
  if( isAutoProxy && (zPath!=NULL) && (!noLock) && pVfs->xOpen ){
    char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
       * 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 
           */







|



















|







7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219
7220
7221
7222
7223
7224
7225
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
       * 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) ){
        storeLastErrno(pFile, 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 ){
          storeLastErrno(pFile, 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 
           */
7195
7196
7197
7198
7199
7200
7201
7202
7203
7204
7205
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219
7220
    int forceNewLockPath = 0;
    
    OSTRACE(("TAKECONCH  %d for %s pid=%d\n", conchFile->h,
             (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid()));

    rc = proxyGetHostID(myHostID, &pError);
    if( (rc&0xff)==SQLITE_IOERR ){
      pFile->lastErrno = pError;
      goto end_takeconch;
    }
    rc = proxyConchLock(pFile, myHostID, SHARED_LOCK);
    if( rc!=SQLITE_OK ){
      goto end_takeconch;
    }
    /* read the existing conch file */
    readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN);
    if( readLen<0 ){
      /* I/O error: lastErrno set by seekAndRead */
      pFile->lastErrno = conchFile->lastErrno;
      rc = SQLITE_IOERR_READ;
      goto end_takeconch;
    }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || 
             readBuf[0]!=(char)PROXY_CONCHVERSION ){
      /* a short read or version format mismatch means we need to create a new 
      ** conch file. 
      */







|










|







7305
7306
7307
7308
7309
7310
7311
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
    int forceNewLockPath = 0;
    
    OSTRACE(("TAKECONCH  %d for %s pid=%d\n", conchFile->h,
             (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"), getpid()));

    rc = proxyGetHostID(myHostID, &pError);
    if( (rc&0xff)==SQLITE_IOERR ){
      storeLastErrno(pFile, pError);
      goto end_takeconch;
    }
    rc = proxyConchLock(pFile, myHostID, SHARED_LOCK);
    if( rc!=SQLITE_OK ){
      goto end_takeconch;
    }
    /* read the existing conch file */
    readLen = seekAndRead((unixFile*)conchFile, 0, readBuf, PROXY_MAXCONCHLEN);
    if( readLen<0 ){
      /* I/O error: lastErrno set by seekAndRead */
      storeLastErrno(pFile, conchFile->lastErrno);
      rc = SQLITE_IOERR_READ;
      goto end_takeconch;
    }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || 
             readBuf[0]!=(char)PROXY_CONCHVERSION ){
      /* a short read or version format mismatch means we need to create a new 
      ** conch file. 
      */
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
    end_takeconch:
      OSTRACE(("TRANSPROXY: CLOSE  %d\n", pFile->h));
      if( rc==SQLITE_OK && pFile->openFlags ){
        int fd;
        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;







|







7446
7447
7448
7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
    end_takeconch:
      OSTRACE(("TRANSPROXY: CLOSE  %d\n", pFile->h));
      if( rc==SQLITE_OK && pFile->openFlags ){
        int fd;
        if( pFile->h>=0 ){
#if defined(STRICT_CLOSE_ERROR) && OSCLOSE_CHECK_CLOSE_IOERR
          if( close(pFile->h) ){
            storeLastErrno(pFile, errno);
            return SQLITE_IOERR_CLOSE;
          }
#else
          robust_close(pFile, pFile->h, __LINE__);
#endif
        }
        pFile->h = -1;
Changes to src/pager.c.
6338
6339
6340
6341
6342
6343
6344









6345
6346
6347
6348
6349
6350
6351
** Return the file handle for the database file associated
** with the pager.  This might return NULL if the file has
** not yet been opened.
*/
sqlite3_file *sqlite3PagerFile(Pager *pPager){
  return pPager->fd;
}










/*
** Return the full pathname of the journal file.
*/
const char *sqlite3PagerJournalname(Pager *pPager){
  return pPager->zJournal;
}







>
>
>
>
>
>
>
>
>







6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
** Return the file handle for the database file associated
** with the pager.  This might return NULL if the file has
** not yet been opened.
*/
sqlite3_file *sqlite3PagerFile(Pager *pPager){
  return pPager->fd;
}

/*
 ** Return the file handle for the WAL journal file associated
 ** with the pager.  This might return NULL if the file has
 ** not yet been opened.
 */
sqlite3_file *sqlite3PagerWalFile(Pager *pPager){
  return ((pPager->pWal) ? sqlite3WalFile(pPager->pWal) : (NULL));
}

/*
** Return the full pathname of the journal file.
*/
const char *sqlite3PagerJournalname(Pager *pPager){
  return pPager->zJournal;
}
Changes to src/pager.h.
150
151
152
153
154
155
156

157
158
159
160
161
162
163
/* Functions used to query pager state and configuration. */
u8 sqlite3PagerIsreadonly(Pager*);
int sqlite3PagerRefcount(Pager*);
int sqlite3PagerMemUsed(Pager*);
const char *sqlite3PagerFilename(Pager*);
const sqlite3_vfs *sqlite3PagerVfs(Pager*);
sqlite3_file *sqlite3PagerFile(Pager*);

const char *sqlite3PagerJournalname(Pager*);
int sqlite3PagerNosync(Pager*);
void *sqlite3PagerTempSpace(Pager*);
int sqlite3PagerIsMemdb(Pager*);
void sqlite3PagerCacheStat(Pager *, int, int, int *);
void sqlite3PagerClearCache(Pager *);








>







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* Functions used to query pager state and configuration. */
u8 sqlite3PagerIsreadonly(Pager*);
int sqlite3PagerRefcount(Pager*);
int sqlite3PagerMemUsed(Pager*);
const char *sqlite3PagerFilename(Pager*);
const sqlite3_vfs *sqlite3PagerVfs(Pager*);
sqlite3_file *sqlite3PagerFile(Pager*);
sqlite3_file *sqlite3PagerWalFile(Pager *pPager);
const char *sqlite3PagerJournalname(Pager*);
int sqlite3PagerNosync(Pager*);
void *sqlite3PagerTempSpace(Pager*);
int sqlite3PagerIsMemdb(Pager*);
void sqlite3PagerCacheStat(Pager *, int, int, int *);
void sqlite3PagerClearCache(Pager *);

Changes to src/sqlite3_private.h.
45
46
47
48
49
50
51

52
53
54
55
56
57
58
59
60
61

62
63
64
65
66
67
68
69
70
71
** behavior is applied and the database file is truncated to zero bytes, a rollback 
** journal (if present) is unlinked, a WAL journal (if present) is truncated to zero 
** bytes and the first few bytes of the -shm file is scrambled to trigger existing
** connections to rebuild the index from the database file contents.
*/
#define SQLITE_FCNTL_TRUNCATE_DATABASE      101
#define SQLITE_TRUNCATE_DATABASE            SQLITE_FCNTL_TRUNCATE_DATABASE

#define SQLITE_TRUNCATE_JOURNALMODE_WAL           (0x1<<0)
#define SQLITE_TRUNCATE_AUTOVACUUM_MASK           (0x3<<2)
#define SQLITE_TRUNCATE_AUTOVACUUM_OFF            (0x1<<2)
#define SQLITE_TRUNCATE_AUTOVACUUM_FULL           (0x2<<2)
#define SQLITE_TRUNCATE_AUTOVACUUM_INCREMENTAL    (0x3<<2)
#define SQLITE_TRUNCATE_PAGESIZE_MASK             (0x7<<4)
#define SQLITE_TRUNCATE_PAGESIZE_1024             (0x1<<4)
#define SQLITE_TRUNCATE_PAGESIZE_2048             (0x2<<4)
#define SQLITE_TRUNCATE_PAGESIZE_4096             (0x3<<4)
#define SQLITE_TRUNCATE_PAGESIZE_8192             (0x4<<4)


/*
** Pass the SQLITE_REPLACE_DATABASE operation code to sqlite3_file_control() 
** and a sqlite3 pointer to another open database file to safely copy the 
** contents of that database file into the receiving database.
*/
#define SQLITE_FCNTL_REPLACE_DATABASE       102
#define SQLITE_REPLACE_DATABASE             SQLITE_FCNTL_REPLACE_DATABASE

#endif







>










>


|







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
** behavior is applied and the database file is truncated to zero bytes, a rollback 
** journal (if present) is unlinked, a WAL journal (if present) is truncated to zero 
** bytes and the first few bytes of the -shm file is scrambled to trigger existing
** connections to rebuild the index from the database file contents.
*/
#define SQLITE_FCNTL_TRUNCATE_DATABASE      101
#define SQLITE_TRUNCATE_DATABASE            SQLITE_FCNTL_TRUNCATE_DATABASE
#define SQLITE_TRUNCATE_INITIALIZE_HEADER_MASK    (0x63<<0)
#define SQLITE_TRUNCATE_JOURNALMODE_WAL           (0x1<<0)
#define SQLITE_TRUNCATE_AUTOVACUUM_MASK           (0x3<<2)
#define SQLITE_TRUNCATE_AUTOVACUUM_OFF            (0x1<<2)
#define SQLITE_TRUNCATE_AUTOVACUUM_FULL           (0x2<<2)
#define SQLITE_TRUNCATE_AUTOVACUUM_INCREMENTAL    (0x3<<2)
#define SQLITE_TRUNCATE_PAGESIZE_MASK             (0x7<<4)
#define SQLITE_TRUNCATE_PAGESIZE_1024             (0x1<<4)
#define SQLITE_TRUNCATE_PAGESIZE_2048             (0x2<<4)
#define SQLITE_TRUNCATE_PAGESIZE_4096             (0x3<<4)
#define SQLITE_TRUNCATE_PAGESIZE_8192             (0x4<<4)
#define SQLITE_TRUNCATE_FORCE                     (0x1<<7)

/*
** Pass the SQLITE_REPLACE_DATABASE operation code to sqlite3_file_control()
** and a sqlite3 pointer to another open database file to safely copy the 
** contents of that database file into the receiving database.
*/
#define SQLITE_FCNTL_REPLACE_DATABASE       102
#define SQLITE_REPLACE_DATABASE             SQLITE_FCNTL_REPLACE_DATABASE

#endif
Changes to src/test_config.c.
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
  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








>
>
>
>
>











>
>
>
>
>







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
  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 defined(SQLITE_ENABLE_PURGEABLE_PCACHE) && defined(__APPLE__)
  Tcl_SetVar2(interp,"sqlite_options","enable_purgeable_pcache","1",TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp,"sqlite_options","enable_purgeable_pcache","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
#if SQLITE_ENABLE_PERSIST_WAL
  Tcl_SetVar2(interp,"sqlite_options","enable_persist_wal","1",TCL_GLOBAL_ONLY);
#else
  Tcl_SetVar2(interp,"sqlite_options","enable_persist_wal","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/wal.c.
2419
2420
2421
2422
2423
2424
2425









2426
2427
2428
2429
2430
2431
2432
Pgno sqlite3WalDbsize(Wal *pWal){
  if( pWal && ALWAYS(pWal->readLock>=0) ){
    return pWal->hdr.nPage;
  }
  return 0;
}











/* 
** This function starts a write transaction on the WAL.
**
** A read transaction must have already been started by a prior call
** to sqlite3WalBeginReadTransaction().
**







>
>
>
>
>
>
>
>
>







2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
Pgno sqlite3WalDbsize(Wal *pWal){
  if( pWal && ALWAYS(pWal->readLock>=0) ){
    return pWal->hdr.nPage;
  }
  return 0;
}

/* 
 ** Return the file for this Wal journal (or zero, if unknown).
 */
sqlite3_file *sqlite3WalFile(Wal *pWal){
  if( pWal ){
    return pWal->pWalFd;
  }
  return 0;
}

/* 
** This function starts a write transaction on the WAL.
**
** A read transaction must have already been started by a prior call
** to sqlite3WalBeginReadTransaction().
**
Changes to src/wal.h.
72
73
74
75
76
77
78



79
80
81
82
83
84
85

/* Read a page from the write-ahead log, if it is present. */
int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);

/* If the WAL is not empty, return the size of the database. */
Pgno sqlite3WalDbsize(Wal *pWal);




/* Obtain or release the WRITER lock. */
int sqlite3WalBeginWriteTransaction(Wal *pWal);
int sqlite3WalEndWriteTransaction(Wal *pWal);

/* Undo any frames written (but not committed) to the log */
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);








>
>
>







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

/* Read a page from the write-ahead log, if it is present. */
int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);

/* If the WAL is not empty, return the size of the database. */
Pgno sqlite3WalDbsize(Wal *pWal);

/* If a WAL journal file has been created, return it */
sqlite3_file *sqlite3WalFile(Wal *pWal);
  
/* Obtain or release the WRITER lock. */
int sqlite3WalBeginWriteTransaction(Wal *pWal);
int sqlite3WalEndWriteTransaction(Wal *pWal);

/* Undo any frames written (but not committed) to the log */
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);

Changes to test/cache.test.
103
104
105
106
107
108
109


110
111
112
113
114


115

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132


133

134
135
136


137

138
139
140
do_test cache-2.3.2 { pager_cache_size db } 2
do_execsql_test cache-2.3.3 {
    INSERT INTO t2 VALUES(1, 2);
    PRAGMA lock_status;
} {main exclusive temp closed}
do_test cache-2.3.4 { pager_cache_size db } 2
do_execsql_test cache-2.3.5 COMMIT


do_test cache-2.3.6 { pager_cache_size db } 1

do_execsql_test cache-2.3.7 {
  SELECT * FROM t1 UNION SELECT * FROM t2;
} {1 2 i j x y}


do_test cache-2.3.8 { pager_cache_size db } 1


# Tests for cache_size = 0.
#
do_execsql_test cache-2.4.1 {
  PRAGMA cache_size = 0;
  BEGIN;
    INSERT INTO t1 VALUES(1, 2);
    PRAGMA lock_status;
} {main reserved temp closed}
do_test cache-2.4.2 { pager_cache_size db } 2
do_execsql_test cache-2.4.3 {
    INSERT INTO t2 VALUES(1, 2);
    PRAGMA lock_status;
} {main exclusive temp closed}
do_test cache-2.4.4 { pager_cache_size db } 2
do_execsql_test cache-2.4.5 COMMIT



do_test cache-2.4.6 { pager_cache_size db } 0

do_execsql_test cache-2.4.7 {
  SELECT * FROM t1 UNION SELECT * FROM t2;
} {1 2 i j x y}


do_test cache-2.4.8 { pager_cache_size db } 0


sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
finish_test







>
>
|
|



>
>
|
>

















>
>
|
>



>
>
|
>



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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
do_test cache-2.3.2 { pager_cache_size db } 2
do_execsql_test cache-2.3.3 {
    INSERT INTO t2 VALUES(1, 2);
    PRAGMA lock_status;
} {main exclusive temp closed}
do_test cache-2.3.4 { pager_cache_size db } 2
do_execsql_test cache-2.3.5 COMMIT
if !$::sqlite_options(enable_purgeable_pcache) {
  # purgeable pcache doesn't share cache between connections
  do_test cache-2.3.6 { pager_cache_size db } 1
}
do_execsql_test cache-2.3.7 {
  SELECT * FROM t1 UNION SELECT * FROM t2;
} {1 2 i j x y}
if !$::sqlite_options(enable_purgeable_pcache) {
  # purgeable pcache doesn't share cache between connections
  do_test cache-2.3.8 { pager_cache_size db } 1
}

# Tests for cache_size = 0.
#
do_execsql_test cache-2.4.1 {
  PRAGMA cache_size = 0;
  BEGIN;
    INSERT INTO t1 VALUES(1, 2);
    PRAGMA lock_status;
} {main reserved temp closed}
do_test cache-2.4.2 { pager_cache_size db } 2
do_execsql_test cache-2.4.3 {
    INSERT INTO t2 VALUES(1, 2);
    PRAGMA lock_status;
} {main exclusive temp closed}
do_test cache-2.4.4 { pager_cache_size db } 2
do_execsql_test cache-2.4.5 COMMIT

if !$::sqlite_options(enable_purgeable_pcache) {
  # purgeable pcache doesn't share cache between connections
  do_test cache-2.4.6 { pager_cache_size db } 0
}
do_execsql_test cache-2.4.7 {
  SELECT * FROM t1 UNION SELECT * FROM t2;
} {1 2 i j x y}
if !$::sqlite_options(enable_purgeable_pcache) {
  # purgeable pcache doesn't share cache between connections
  do_test cache-2.4.8 { pager_cache_size db } 0
}

sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
finish_test
Changes to test/dbstatus2.test.
34
35
36
37
38
39
40



41
42
43
44
45
46
47
}

proc db_write {db {reset 0}} {
  sqlite3_db_status $db CACHE_WRITE $reset
}

do_test 1.1 {



  db close
  sqlite3 db test.db
  expr {[file size test.db] / 1024}
} 6

do_test 1.2 {
  execsql { SELECT b FROM t1 WHERE a=2 }







>
>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
}

proc db_write {db {reset 0}} {
  sqlite3_db_status $db CACHE_WRITE $reset
}

do_test 1.1 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  sqlite3 db test.db
  expr {[file size test.db] / 1024}
} 6

do_test 1.2 {
  execsql { SELECT b FROM t1 WHERE a=2 }
Changes to test/fallocate.test.
77
78
79
80
81
82
83





84


85

86
87

88
89
90
91
92
93
94
}]
ifcapable !wal { set skipwaltests 1 }
if {![wal_is_ok]} { set skipwaltests 1 }

if {!$skipwaltests} {
  db close
  forcedelete 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;
      CREATE TABLE t1(a, b);
    }
    file size test.db







>
>
>
>
>
|
>
>

>
|
|
>







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
}]
ifcapable !wal { set skipwaltests 1 }
if {![wal_is_ok]} { set skipwaltests 1 }

if {!$skipwaltests} {
  db close
  forcedelete test.db
  ifcapable enable_persist_wal {
    forcedelete test.db-journal
    forcedelete test.db-wal
    forcedelete test.db-shm
  }
  if {[forced_proxy_locking]} { 
    forcedelete .test.db-conch
  }
  sqlite3 db test.db
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  file_control_chunksize_test db main [expr 32*1024]
  do_test fallocate-2.1 {
    execsql {
      PRAGMA page_size = 1024;
      PRAGMA journal_mode = WAL;
      CREATE TABLE t1(a, b);
    }
    file size test.db
Changes to test/memsubsys1.test.
94
95
96
97
98
99
100

101
102
103

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

122
123
124
125
126
127

128
129
130
131
132
133
134
sqlite3_config_pagecache [expr 1024+$xtra_size] 20
sqlite3_initialize
reset_highwater_marks
build_test_db memsubsys1-2 {PRAGMA page_size=1024}
#show_memstats
set MEMORY_MANAGEMENT $sqlite_options(memorymanage)
ifcapable !malloc_usable_size {

 do_test memsubsys1-2.3 {
    set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
  } [expr ($TEMP_STORE>1 || $MEMORY_MANAGEMENT==0)*1024]

}
do_test memsubsys1-2.4 {
  set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
} 20
do_test memsubsys1-2.5 {
  set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
} 0

# Test 3:  Activate PAGECACHE with 20 pages but use the wrong page size
# so that PAGECACHE is not used.
#
db close
sqlite3_shutdown
sqlite3_config_pagecache [expr 512+$xtra_size] 20
sqlite3_initialize
reset_highwater_marks
build_test_db memsubsys1-3.1 {PRAGMA page_size=1024}
#show_memstats

do_test memsubsys1-3.1.3 {
  set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
} 0
do_test memsubsys1-3.1.4 {
  set overflow [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
} $max_pagecache

do_test memsubsys1-3.1.5 {
  set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
} 0
db close
sqlite3_shutdown
sqlite3_config_pagecache [expr 2048+$xtra_size] 20
sqlite3_initialize







>
|
|
|
>


















>
|
|
|
|
|
|
>







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
sqlite3_config_pagecache [expr 1024+$xtra_size] 20
sqlite3_initialize
reset_highwater_marks
build_test_db memsubsys1-2 {PRAGMA page_size=1024}
#show_memstats
set MEMORY_MANAGEMENT $sqlite_options(memorymanage)
ifcapable !malloc_usable_size {
  if !$::sqlite_options(enable_purgeable_pcache) {
    do_test memsubsys1-2.3 {
      set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
    } [expr ($TEMP_STORE>1 || $MEMORY_MANAGEMENT==0)*1024]
  }
}
do_test memsubsys1-2.4 {
  set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
} 20
do_test memsubsys1-2.5 {
  set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
} 0

# Test 3:  Activate PAGECACHE with 20 pages but use the wrong page size
# so that PAGECACHE is not used.
#
db close
sqlite3_shutdown
sqlite3_config_pagecache [expr 512+$xtra_size] 20
sqlite3_initialize
reset_highwater_marks
build_test_db memsubsys1-3.1 {PRAGMA page_size=1024}
#show_memstats
if !$::sqlite_options(enable_purgeable_pcache) {
  do_test memsubsys1-3.1.3 {
    set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
  } 0
  do_test memsubsys1-3.1.4 {
    set overflow [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
  } $max_pagecache
}
do_test memsubsys1-3.1.5 {
  set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
} 0
db close
sqlite3_shutdown
sqlite3_config_pagecache [expr 2048+$xtra_size] 20
sqlite3_initialize
155
156
157
158
159
160
161

162
163
164

165
166
167
168
169
170
171
reset_highwater_marks
build_test_db memsubsys1-4 {PRAGMA page_size=1024}
#show_memstats
do_test memsubsys1-4.3 {
  set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
  expr {$pg_used>=45 && $pg_used<=50}
} 1

do_test memsubsys1-4.4 {
  set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
} 0

do_test memsubsys1-4.5 {
  set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
  expr {$maxreq<7000}
} 1
do_test memsubsys1-4.6 {
  set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
} 1







>
|
|
|
>







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
reset_highwater_marks
build_test_db memsubsys1-4 {PRAGMA page_size=1024}
#show_memstats
do_test memsubsys1-4.3 {
  set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
  expr {$pg_used>=45 && $pg_used<=50}
} 1
if !$::sqlite_options(enable_purgeable_pcache) {
  do_test memsubsys1-4.4 {
    set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
  } 0
}
do_test memsubsys1-4.5 {
  set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
  expr {$maxreq<7000}
} 1
do_test memsubsys1-4.6 {
  set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
} 1
240
241
242
243
244
245
246

247
248
249
250
251
252
253

254
255
256
257
258
259
260
  PRAGMA temp_store=memory;
}
#show_memstats
do_test memsubsys1-7.3 {
  set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
  expr {$pg_used<24}
} 1

do_test memsubsys1-7.4 {
  set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
} 0
do_test memsubsys1-7.5 {
  set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
  expr {$maxreq<4100}
} 1

do_test memsubsys1-7.6 {
  set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
} 1
do_test memsubsys1-7.7 {
  set s_ovfl [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]
} 0








>
|
|
|
|
|
|
|
>







246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
  PRAGMA temp_store=memory;
}
#show_memstats
do_test memsubsys1-7.3 {
  set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
  expr {$pg_used<24}
} 1
if !$::sqlite_options(enable_purgeable_pcache) {
  do_test memsubsys1-7.4 {
    set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2]
  } 0
  do_test memsubsys1-7.5 {
    set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2]
    expr {$maxreq<4100}
  } 1
}
do_test memsubsys1-7.6 {
  set s_used [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] 2]
} 1
do_test memsubsys1-7.7 {
  set s_ovfl [lindex [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] 2]
} 0

Changes to test/pager1.test.
1158
1159
1160
1161
1162
1163
1164



1165
1166
1167
1168
1169
1170
1171
    7  { INSERT INTO t1 VALUES(5, 6); } {}        -1 [wal_file_size 2 1024]
  
    8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
    9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
    10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
  
  }] {



    do_execsql_test pager1-7.1.$tn.1 $sql $res
    catch { set J -1 ; set J [file size test.db-journal] }
    catch { set W -1 ; set W [file size test.db-wal] }
    do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
  }
}








>
>
>







1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
    7  { INSERT INTO t1 VALUES(5, 6); } {}        -1 [wal_file_size 2 1024]
  
    8  { PRAGMA journal_mode = TRUNCATE } truncate          0 -1
    9  { INSERT INTO t1 VALUES(7, 8) }    {}                0 -1
    10 { SELECT * FROM t1 }               {1 2 3 4 5 6 7 8} 0 -1
  
  }] {
    ifcapable enable_persist_wal {
      file_control_persist_wal db 0
    }
    do_execsql_test pager1-7.1.$tn.1 $sql $res
    catch { set J -1 ; set J [file size test.db-journal] }
    catch { set W -1 ; set W [file size test.db-wal] }
    do_test pager1-7.1.$tn.2 { list $J $W } [list $js $ws]
  }
}

Changes to test/pcache.test.
112
113
114
115
116
117
118
119


120
121
122
123
124
125
126
  pcache_stats
} {current 24 max 22 min 20 recyclable 0}

# Rolling back the transaction held by db2 at this point releases a pinned
# page. Because the number of allocated pages is greater than the 
# configured maximum, this page should be freed immediately instead of
# recycled.
#


do_test pcache-1.8 {
  execsql {ROLLBACK} db2
  pcache_stats
} {current 23 max 22 min 20 recyclable 0}

do_test pcache-1.9 {
  execsql COMMIT







|
>
>







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  pcache_stats
} {current 24 max 22 min 20 recyclable 0}

# Rolling back the transaction held by db2 at this point releases a pinned
# page. Because the number of allocated pages is greater than the 
# configured maximum, this page should be freed immediately instead of
# recycled.
# Note- purgable_pcache doesn't share caches between connections and these tests
# are only useful for testing that feature.  
if !$::sqlite_options(enable_purgeable_pcache) {
do_test pcache-1.8 {
  execsql {ROLLBACK} db2
  pcache_stats
} {current 23 max 22 min 20 recyclable 0}

do_test pcache-1.9 {
  execsql COMMIT
173
174
175
176
177
178
179


180

181
    SELECT * FROM t6 ORDER BY a; SELECT * FROM t6;
    SELECT * FROM t7 ORDER BY a; SELECT * FROM t7;
    SELECT * FROM t8 ORDER BY a; SELECT * FROM t8;
    SELECT * FROM t9 ORDER BY a; SELECT * FROM t9;
  }
  pcache_stats
} {current 14 max 15 min 10 recyclable 14}




finish_test







>
>
|
>

175
176
177
178
179
180
181
182
183
184
185
186
    SELECT * FROM t6 ORDER BY a; SELECT * FROM t6;
    SELECT * FROM t7 ORDER BY a; SELECT * FROM t7;
    SELECT * FROM t8 ORDER BY a; SELECT * FROM t8;
    SELECT * FROM t9 ORDER BY a; SELECT * FROM t9;
  }
  pcache_stats
} {current 14 max 15 min 10 recyclable 14}
} else {
  db2 close
}

finish_test
Changes to test/shrink.test.
12
13
14
15
16
17
18





19
20
21
22
23
24
25
# This file contains test cases for sqlite3_db_release_memory and
# the PRAGMA shrink_memory statement.
#

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






unset -nocomplain baseline
do_test shrink-1.1 {
  db eval {
    PRAGMA cache_size = 2000;
    CREATE TABLE t1(x,y);
    INSERT INTO t1 VALUES(randomblob(1000000),1);
  }







>
>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# This file contains test cases for sqlite3_db_release_memory and
# the PRAGMA shrink_memory statement.
#

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

# purgeable pcache tracks memory differently
ifcapable {enable_purgeable_pcache} {
  finish_test
  return
}
unset -nocomplain baseline
do_test shrink-1.1 {
  db eval {
    PRAGMA cache_size = 2000;
    CREATE TABLE t1(x,y);
    INSERT INTO t1 VALUES(randomblob(1000000),1);
  }
Changes to test/wal.test.
172
173
174
175
176
177
178



179
180
181
182
183
184
185
  execsql {
    COMMIT;
    SELECT * FROM t1;
  }
} {a b}

do_test wal-4.4.1 {



  db close
  sqlite3 db test.db
  db func blob blob
  list [execsql { SELECT * FROM t1 }] [file size test.db-wal]
} {{a b} 0}
do_test wal-4.4.2 {
  execsql { PRAGMA cache_size = 10 }







>
>
>







172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  execsql {
    COMMIT;
    SELECT * FROM t1;
  }
} {a b}

do_test wal-4.4.1 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  sqlite3 db test.db
  db func blob blob
  list [execsql { SELECT * FROM t1 }] [file size test.db-wal]
} {{a b} 0}
do_test wal-4.4.2 {
  execsql { PRAGMA cache_size = 10 }
223
224
225
226
227
228
229



230
231
232
233
234
235
236
do_test wal-4.4.7 {
  execsql { PRAGMA integrity_check } db2
} {ok}
db2 close

do_test wal-4.5.1 {
  reopen_db



  db func blob blob
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES('a', 'b');
  }
  sqlite3 db test.db







>
>
>







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
do_test wal-4.4.7 {
  execsql { PRAGMA integrity_check } db2
} {ok}
db2 close

do_test wal-4.5.1 {
  reopen_db
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db func blob blob
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES('a', 'b');
  }
  sqlite3 db test.db
337
338
339
340
341
342
343



344
345
346
347
348
349
350

foreach sector {512 4096} {
  sqlite3_simulate_device -sectorsize $sector
  foreach pgsz {512 1024 2048 4096} {
    forcedelete test.db test.db-wal
    do_test wal-6.$sector.$pgsz.1 {
      sqlite3 db test.db -vfs devsym



      execsql "
        PRAGMA page_size = $pgsz;
        PRAGMA auto_vacuum = 0;
        PRAGMA journal_mode = wal;
      "
      execsql "
        CREATE TABLE t1(a, b);







>
>
>







343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359

foreach sector {512 4096} {
  sqlite3_simulate_device -sectorsize $sector
  foreach pgsz {512 1024 2048 4096} {
    forcedelete test.db test.db-wal
    do_test wal-6.$sector.$pgsz.1 {
      sqlite3 db test.db -vfs devsym
      ifcapable enable_persist_wal {
        file_control_persist_wal db 0
      }
      execsql "
        PRAGMA page_size = $pgsz;
        PRAGMA auto_vacuum = 0;
        PRAGMA journal_mode = wal;
      "
      execsql "
        CREATE TABLE t1(a, b);
723
724
725
726
727
728
729



730
731
732
733



734
735
736
737
738
739
740
  }
} {16 ok}
do_test wal-11.8 {
  execsql { PRAGMA wal_checkpoint }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size 41 1024]]
do_test wal-11.9 {



  db close
  list [expr [file size test.db]/1024] [log_deleted test.db-wal]
} {37 1}
sqlite3_wal db test.db



do_test wal-11.10 {
  execsql {
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 32
      SELECT count(*) FROM t1;
  }







>
>
>




>
>
>







732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  }
} {16 ok}
do_test wal-11.8 {
  execsql { PRAGMA wal_checkpoint }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size 41 1024]]
do_test wal-11.9 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  list [expr [file size test.db]/1024] [log_deleted test.db-wal]
} {37 1}
sqlite3_wal db test.db
ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
do_test wal-11.10 {
  execsql {
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t1 SELECT blob(900) FROM t1;   -- 32
      SELECT count(*) FROM t1;
  }
774
775
776
777
778
779
780



781
782
783
784
785
786
787
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(x, y);
    INSERT INTO t1 VALUES('A', 1);
  }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 1 [wal_file_size 5 1024]]
do_test wal-12.2 {



  db close
  sqlite3 db test.db
  execsql {
    PRAGMA synchronous = normal;
    UPDATE t1 SET y = 0 WHERE x = 'A';
  }
  list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]







>
>
>







789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
    CREATE TABLE t1(x, y);
    CREATE TABLE t2(x, y);
    INSERT INTO t1 VALUES('A', 1);
  }
  list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 1 [wal_file_size 5 1024]]
do_test wal-12.2 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  sqlite3 db test.db
  execsql {
    PRAGMA synchronous = normal;
    UPDATE t1 SET y = 0 WHERE x = 'A';
  }
  list [expr [file size test.db]/1024] [expr [file size test.db-wal]/1044]
811
812
813
814
815
816
817



818
819
820
821
822
823
824
do_test wal-12.6 {
  forcecopy test.db test2.db
  forcecopy test.db-wal test2.db-wal
  sqlite3_wal db2 test2.db
  execsql { SELECT * FROM t2 } db2
} {B 2}
db2 close



db close

#-------------------------------------------------------------------------
# Test large log summaries.
#
# In this case "large" usually means a log file that requires a wal-index
# mapping larger than 64KB (the default initial allocation). A 64KB wal-index







>
>
>







829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
do_test wal-12.6 {
  forcecopy test.db test2.db
  forcecopy test.db-wal test2.db-wal
  sqlite3_wal db2 test2.db
  execsql { SELECT * FROM t2 } db2
} {B 2}
db2 close
ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
db close

#-------------------------------------------------------------------------
# Test large log summaries.
#
# In this case "large" usually means a log file that requires a wal-index
# mapping larger than 64KB (the default initial allocation). A 64KB wal-index
851
852
853
854
855
856
857



858
859
860
861
862
863
864
  puts $fd ""
  close $fd
  sqlite3 db test.db
  execsql { SELECT * FROM t2 }
} {B 2}
breakpoint
do_test wal-13.1.3 {



  db close
  file exists test.db-wal
} {0}

do_test wal-13.2.1 {
  sqlite3 db test.db
  execsql { SELECT count(*) FROM t2 }







>
>
>







872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
  puts $fd ""
  close $fd
  sqlite3 db test.db
  execsql { SELECT * FROM t2 }
} {B 2}
breakpoint
do_test wal-13.1.3 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  file exists test.db-wal
} {0}

do_test wal-13.2.1 {
  sqlite3 db test.db
  execsql { SELECT count(*) FROM t2 }
1345
1346
1347
1348
1349
1350
1351



1352
1353
1354
1355
1356
1357
1358
do_test wal-19.2 {
  execsql {
    INSERT INTO t1 VALUES(5, 6);
    SELECT * FROM t1;
  }
} {1 2 3 4 5 6}
do_test wal-19.3 {



  db close
  db2 close
  file exists test.db-wal
} {0}
do_test wal-19.4 {
  # When the bug was present, the following was returning {1 2 3 4} only,
  # as [db2] had an out-of-date copy of the wal-index header when it was







>
>
>







1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
do_test wal-19.2 {
  execsql {
    INSERT INTO t1 VALUES(5, 6);
    SELECT * FROM t1;
  }
} {1 2 3 4 5 6}
do_test wal-19.3 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db2 0
  }
  db close
  db2 close
  file exists test.db-wal
} {0}
do_test wal-19.4 {
  # When the bug was present, the following was returning {1 2 3 4} only,
  # as [db2] had an out-of-date copy of the wal-index header when it was
1491
1492
1493
1494
1495
1496
1497



1498
1499
1500
1501
1502
1503
1504
  faultsim_delete_and_reopen
  execsql {
    CREATE TABLE t1(a, b);
    PRAGMA journal_mode = WAL;
    INSERT INTO t1 VALUES(1, 2);
    INSERT INTO t1 VALUES(3, 4);
  }



  faultsim_save_and_close

  sqlite3_shutdown
  test_sqlite3_log [list lappend ::log]
  set ::log [list]
  sqlite3 db test.db
  execsql { SELECT * FROM t1 }







>
>
>







1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
  faultsim_delete_and_reopen
  execsql {
    CREATE TABLE t1(a, b);
    PRAGMA journal_mode = WAL;
    INSERT INTO t1 VALUES(1, 2);
    INSERT INTO t1 VALUES(3, 4);
  }
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  faultsim_save_and_close

  sqlite3_shutdown
  test_sqlite3_log [list lappend ::log]
  set ::log [list]
  sqlite3 db test.db
  execsql { SELECT * FROM t1 }
1537
1538
1539
1540
1541
1542
1543



1544
1545
1546
1547
1548
1549
1550
    INSERT INTO t1 VALUES(randomblob(5000));
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
  } {wal}
  do_test 24.2 { 



    execsql {
      DELETE FROM t1;
      PRAGMA wal_checkpoint;
    }
    db close
    sqlite3 db test.db
    file exists test.db-wal







>
>
>







1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
    INSERT INTO t1 VALUES(randomblob(5000));
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
    INSERT INTO t1 SELECT * FROM t1;
  } {wal}
  do_test 24.2 { 
    ifcapable enable_persist_wal {
      file_control_persist_wal db 0
    }
    execsql {
      DELETE FROM t1;
      PRAGMA wal_checkpoint;
    }
    db close
    sqlite3 db test.db
    file exists test.db-wal
1565
1566
1567
1568
1569
1570
1571



1572
1573
1574
1575
1576
1577
  # It would be two frames (the new root page and a padding frame) if the
  # ZERO_DAMAGE flag were not set.
  do_test 24.5 {
    file size test.db-wal
  } [wal_file_size 1 1024]
}




db close
sqlite3_shutdown
test_sqlite3_log
sqlite3_initialize

finish_test







>
>
>






1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
  # It would be two frames (the new root page and a padding frame) if the
  # ZERO_DAMAGE flag were not set.
  do_test 24.5 {
    file size test.db-wal
  } [wal_file_size 1 1024]
}

ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
db close
sqlite3_shutdown
test_sqlite3_log
sqlite3_initialize

finish_test
Changes to test/wal2.test.
572
573
574
575
576
577
578



579
580
581



582
583
584
585
586
587
588
      INSERT INTO t1 VALUES('Chico');
      INSERT INTO t1 VALUES('Harpo');
    COMMIT;
  }
  list [file exists test.db-wal] [file exists test.db-journal]
} {1 0}
do_test wal2-6.3.2 {



  execsql { PRAGMA journal_mode = DELETE }
  file exists test.db-wal
} {0}



do_test wal2-6.3.3 {
  execsql { PRAGMA lock_status }
} {main exclusive temp closed}
do_test wal2-6.3.4 {
  execsql { 
    BEGIN;
      INSERT INTO t1 VALUES('Groucho');







>
>
>



>
>
>







572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
      INSERT INTO t1 VALUES('Chico');
      INSERT INTO t1 VALUES('Harpo');
    COMMIT;
  }
  list [file exists test.db-wal] [file exists test.db-journal]
} {1 0}
do_test wal2-6.3.2 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  execsql { PRAGMA journal_mode = DELETE }
  file exists test.db-wal
} {0}
do_test wal2-6.3.2.1 {
  execsql { PRAGMA journal_mode; }
} {delete}
do_test wal2-6.3.3 {
  execsql { PRAGMA lock_status }
} {main exclusive temp closed}
do_test wal2-6.3.4 {
  execsql { 
    BEGIN;
      INSERT INTO t1 VALUES('Groucho');
721
722
723
724
725
726
727


728
729
730
731
732
733
734
735
    if {[string match {#*} $sq]==0} {append S "$sq\n"}
  }

  set ::locks [list]
  do_test wal2-6.4.$tn.1 { execsql $S } $res
  do_test wal2-6.4.$tn.2 { set ::locks  } $L
}



db close
tvfs delete

do_test wal2-6.5.1 {
  sqlite3 db test.db
  execsql {
    PRAGMA auto_vacuum = 0;







>
>
|







727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
    if {[string match {#*} $sq]==0} {append S "$sq\n"}
  }

  set ::locks [list]
  do_test wal2-6.4.$tn.1 { execsql $S } $res
  do_test wal2-6.4.$tn.2 { set ::locks  } $L
}
ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
db close
tvfs delete

do_test wal2-6.5.1 {
  sqlite3 db test.db
  execsql {
    PRAGMA auto_vacuum = 0;
1092
1093
1094
1095
1096
1097
1098



1099
1100
1101
1102
1103
1104
1105
      execsql { INSERT INTO tx DEFAULT VALUES }
      list [file exists test.db-wal] [file exists $shmpath]
    } {1 1}
    do_test wal2-12.2.$tn.4 {
      list [file attr test.db-wal -perm] [file attr $shmpath -perm]
    } [list $effective $effective]
    do_test wal2-12.2.$tn.5 {



      db close
      list [file exists test.db-wal] [file exists $shmpath]
    } {0 0}
  }
}

#-------------------------------------------------------------------------







>
>
>







1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
      execsql { INSERT INTO tx DEFAULT VALUES }
      list [file exists test.db-wal] [file exists $shmpath]
    } {1 1}
    do_test wal2-12.2.$tn.4 {
      list [file attr test.db-wal -perm] [file attr $shmpath -perm]
    } [list $effective $effective]
    do_test wal2-12.2.$tn.5 {
      ifcapable enable_persist_wal {
        file_control_persist_wal db 0
      }
      db close
      list [file exists test.db-wal] [file exists $shmpath]
    } {0 0}
  }
}

#-------------------------------------------------------------------------
Changes to test/wal5.test.
75
76
77
78
79
80
81





82
83
84
85
86
87
88
    proc busyhandler {n} {
      incr ::nBusyHandler 
      eval $::busy_handler_script
      return 0
    }

    proc reopen_all {} {





      code1 {db close}
      code2 {db2 close}
      code3 {db3 close}

      code1 {sqlite3 db test.db}
      code2 {sqlite3 db2 test.db}
      code3 {sqlite3 db3 test.db}







>
>
>
>
>







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    proc busyhandler {n} {
      incr ::nBusyHandler 
      eval $::busy_handler_script
      return 0
    }

    proc reopen_all {} {
      ifcapable enable_persist_wal {
        code1 { file_control_persist_wal db 0 }
        code2 { file_control_persist_wal db2 0 }
        code3 { file_control_persist_wal db3 0 }
      }
      code1 {db close}
      code2 {db2 close}
      code3 {db3 close}

      code1 {sqlite3 db test.db}
      code2 {sqlite3 db2 test.db}
      code3 {sqlite3 db3 test.db}
324
325
326
327
328
329
330





331
332
333
334
335
336
337

    do_test 3.$tn.2 { code2 { do_wal_checkpoint db2 } } {0 2 2}

    do_test 3.$tn.3 { code2 { do_wal_checkpoint db2 } } {0 2 2}

    do_test 3.$tn.4 { code3 { do_wal_checkpoint db3 } } {0 2 2}






    code1 {db  close}
    code2 {db2 close}
    code3 {db3 close}

    code1 {sqlite3 db  test.db}
    code2 {sqlite3 db2 test.db}
    code3 {sqlite3 db3 test.db}







>
>
>
>
>







329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

    do_test 3.$tn.2 { code2 { do_wal_checkpoint db2 } } {0 2 2}

    do_test 3.$tn.3 { code2 { do_wal_checkpoint db2 } } {0 2 2}

    do_test 3.$tn.4 { code3 { do_wal_checkpoint db3 } } {0 2 2}

    ifcapable enable_persist_wal {
      code1 { file_control_persist_wal db 0 }
      code2 { file_control_persist_wal db2 0 }
      code3 { file_control_persist_wal db3 0 }
    }
    code1 {db  close}
    code2 {db2 close}
    code3 {db3 close}

    code1 {sqlite3 db  test.db}
    code2 {sqlite3 db2 test.db}
    code3 {sqlite3 db3 test.db}
Changes to test/walbak.test.
319
320
321
322
323
324
325



326
327
328
329
330
331
332
333



334
335
336
337
338
339
340
  catch { db close } 
  catch { db2 close } 
  forcedelete test.db test.db2

  do_test walbak-4.$tn.1 {
    sqlite3 db test.db
    db eval "PRAGMA journal_mode = $src"



    db eval {
      CREATE TABLE t1(a, b);
      INSERT INTO t1 VALUES('I', 'II');
      INSERT INTO t1 VALUES('III', 'IV');
    }

    sqlite3 db2 test.db2
    db2 eval "PRAGMA journal_mode = $dest"



    db2 eval {
      CREATE TABLE t2(x, y);
      INSERT INTO t2 VALUES('1', '2');
      INSERT INTO t2 VALUES('3', '4');
    }
  } {}








>
>
>








>
>
>







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
  catch { db close } 
  catch { db2 close } 
  forcedelete test.db test.db2

  do_test walbak-4.$tn.1 {
    sqlite3 db test.db
    db eval "PRAGMA journal_mode = $src"
    ifcapable enable_persist_wal {
      file_control_persist_wal db 0
    }
    db eval {
      CREATE TABLE t1(a, b);
      INSERT INTO t1 VALUES('I', 'II');
      INSERT INTO t1 VALUES('III', 'IV');
    }

    sqlite3 db2 test.db2
    db2 eval "PRAGMA journal_mode = $dest"
    ifcapable enable_persist_wal {
      file_control_persist_wal db2 0
    }
    db2 eval {
      CREATE TABLE t2(x, y);
      INSERT INTO t2 VALUES('1', '2');
      INSERT INTO t2 VALUES('3', '4');
    }
  } {}

Changes to test/walhook.test.
68
69
70
71
72
73
74



75
76



77
78
79
80
81
82
83
    return 0
  }
  execsql { CREATE TABLE t3(a PRIMARY KEY, b) }
  file size test.db
} [expr 6*1024]

db2 close



db close
sqlite3 db test.db



do_test walhook-2.1 {
  execsql { PRAGMA synchronous = NORMAL }
  execsql { PRAGMA wal_autocheckpoint }
} {1000}
do_test walhook-2.2 {
  execsql { PRAGMA wal_autocheckpoint = 10}
} {10}







>
>
>


>
>
>







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
    return 0
  }
  execsql { CREATE TABLE t3(a PRIMARY KEY, b) }
  file size test.db
} [expr 6*1024]

db2 close
ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
db close
sqlite3 db test.db
ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
do_test walhook-2.1 {
  execsql { PRAGMA synchronous = NORMAL }
  execsql { PRAGMA wal_autocheckpoint }
} {1000}
do_test walhook-2.2 {
  execsql { PRAGMA wal_autocheckpoint = 10}
} {10}
Changes to test/walmode.test.
84
85
86
87
88
89
90



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106



107
108
109
110
111
112
113
  execsql { CREATE TABLE t1(a, b) }
  file size test.db
} {1024}
do_test walmode-1.6 {
  file exists test.db-wal
} {1}
do_test walmode-1.7 {



  db close
  file exists test.db-wal
} {0}

# There is now a database file with the read and write versions set to 2
# in the file system. This file should default to WAL mode.
#
do_test walmode-2.1 {
  sqlite3 db test.db
  file exists test.db-wal
} {0}
do_test walmode-2.2 {
  execsql { SELECT * FROM sqlite_master }
  file exists test.db-wal
} {1}
do_test walmode-2.3 {



  db close
  file exists test.db-wal
} {0}

# If the first statement executed is "PRAGMA journal_mode = wal", and
# the file is already configured for WAL (read and write versions set
# to 2), then there should be no need to write the database. The 







>
>
>
















>
>
>







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  execsql { CREATE TABLE t1(a, b) }
  file size test.db
} {1024}
do_test walmode-1.6 {
  file exists test.db-wal
} {1}
do_test walmode-1.7 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  file exists test.db-wal
} {0}

# There is now a database file with the read and write versions set to 2
# in the file system. This file should default to WAL mode.
#
do_test walmode-2.1 {
  sqlite3 db test.db
  file exists test.db-wal
} {0}
do_test walmode-2.2 {
  execsql { SELECT * FROM sqlite_master }
  file exists test.db-wal
} {1}
do_test walmode-2.3 {
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  db close
  file exists test.db-wal
} {0}

# If the first statement executed is "PRAGMA journal_mode = wal", and
# the file is already configured for WAL (read and write versions set
# to 2), then there should be no need to write the database. The 
122
123
124
125
126
127
128



129
130
131
132
133
134
135
  list $sqlite_sync_count [file exists test.db-wal] [file size test.db-wal]
} {0 1 0}

# Test that changing back to journal_mode=persist works.
#
do_test walmode-4.1 {
  execsql { INSERT INTO t1 VALUES(1, 2) }



  execsql { PRAGMA journal_mode = persist }
} {persist}
do_test walmode-4.2 {
  list [file exists test.db-journal] [file exists test.db-wal]
} {1 0}
do_test walmode-4.3 {
  execsql { SELECT * FROM t1 }







>
>
>







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  list $sqlite_sync_count [file exists test.db-wal] [file size test.db-wal]
} {0 1 0}

# Test that changing back to journal_mode=persist works.
#
do_test walmode-4.1 {
  execsql { INSERT INTO t1 VALUES(1, 2) }
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  execsql { PRAGMA journal_mode = persist }
} {persist}
do_test walmode-4.2 {
  list [file exists test.db-journal] [file exists test.db-wal]
} {1 0}
do_test walmode-4.3 {
  execsql { SELECT * FROM t1 }
145
146
147
148
149
150
151



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168



169
170
171
172
173
174
175

# Test that nothing goes wrong if a connection is prevented from changing
# from WAL to rollback mode because a second connection has the database
# open. Or from rollback to WAL.
#
do_test walmode-4.6 {
  sqlite3 db2 test.db



  execsql { PRAGMA main.journal_mode } db2
} {delete}
do_test walmode-4.7 {
  execsql { PRAGMA main.journal_mode = wal } db
} {wal}
do_test walmode-4.8 {
  execsql { SELECT * FROM t1 } db2
} {1 2}
do_test walmode-4.9 {
  catchsql { PRAGMA journal_mode = delete } db
} {1 {database is locked}}
do_test walmode-4.10 {
  execsql { PRAGMA main.journal_mode } db
} {wal}

do_test walmode-4.11 {
  db2 close



  execsql { PRAGMA journal_mode = delete } db
} {delete}
do_test walmode-4.12 {
  execsql { PRAGMA main.journal_mode } db
} {delete}
do_test walmode-4.13 {
  list [file exists test.db-journal] [file exists test.db-wal]







>
>
>

















>
>
>







154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

# Test that nothing goes wrong if a connection is prevented from changing
# from WAL to rollback mode because a second connection has the database
# open. Or from rollback to WAL.
#
do_test walmode-4.6 {
  sqlite3 db2 test.db
  ifcapable enable_persist_wal {
    file_control_persist_wal db2 0
  }
  execsql { PRAGMA main.journal_mode } db2
} {delete}
do_test walmode-4.7 {
  execsql { PRAGMA main.journal_mode = wal } db
} {wal}
do_test walmode-4.8 {
  execsql { SELECT * FROM t1 } db2
} {1 2}
do_test walmode-4.9 {
  catchsql { PRAGMA journal_mode = delete } db
} {1 {database is locked}}
do_test walmode-4.10 {
  execsql { PRAGMA main.journal_mode } db
} {wal}

do_test walmode-4.11 {
  db2 close
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  execsql { PRAGMA journal_mode = delete } db
} {delete}
do_test walmode-4.12 {
  execsql { PRAGMA main.journal_mode } db
} {delete}
do_test walmode-4.13 {
  list [file exists test.db-journal] [file exists test.db-wal]
315
316
317
318
319
320
321



322
323
324
325
326
327
328
# Test the effect of a "PRAGMA journal_mode" command being the first 
# thing executed by a new connection. This means that the schema is not
# loaded when sqlite3_prepare_v2() is called to compile the statement.
#
do_test walmode-7.0 {
  forcedelete test.db
  sqlite3 db test.db



  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
  }
} {wal}
foreach {tn sql result} {
  1  "PRAGMA journal_mode"                wal







>
>
>







330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# Test the effect of a "PRAGMA journal_mode" command being the first 
# thing executed by a new connection. This means that the schema is not
# loaded when sqlite3_prepare_v2() is called to compile the statement.
#
do_test walmode-7.0 {
  forcedelete test.db
  sqlite3 db test.db
  ifcapable enable_persist_wal {
    file_control_persist_wal db 0
  }
  execsql {
    PRAGMA journal_mode = WAL;
    CREATE TABLE t1(a, b);
  }
} {wal}
foreach {tn sql result} {
  1  "PRAGMA journal_mode"                wal
Changes to test/walnoshm.test.
50
51
52
53
54
55
56



57
58
59
60
61
62
63
do_test 1.5 { file exists test.db-wal } {1}

do_execsql_test 1.6 { INSERT INTO t1 VALUES(3, 4) }

do_execsql_test 1.7 {
  PRAGMA locking_mode = normal;
} {exclusive}



do_execsql_test 1.8 {
  PRAGMA journal_mode = delete;
  PRAGMA main.locking_mode;
} {delete exclusive}
do_execsql_test 1.9 {
  PRAGMA locking_mode = normal;
} {normal}







>
>
>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
do_test 1.5 { file exists test.db-wal } {1}

do_execsql_test 1.6 { INSERT INTO t1 VALUES(3, 4) }

do_execsql_test 1.7 {
  PRAGMA locking_mode = normal;
} {exclusive}
ifcapable enable_persist_wal {
  file_control_persist_wal db 0
}
do_execsql_test 1.8 {
  PRAGMA journal_mode = delete;
  PRAGMA main.locking_mode;
} {delete exclusive}
do_execsql_test 1.9 {
  PRAGMA locking_mode = normal;
} {normal}
Changes to test/walpersist.test.
35
36
37
38
39
40
41

42
43
44





45

46
47
48
49
50
51
52

53
54




55

56
57
58
59
60
61
62
    INSERT INTO t1 VALUES(randomblob(5000));
  }
  file exists test.db-wal
} {1}
do_test walpersist-1.1 {
  file exists $shmpath
} {1}

do_test walpersist-1.2 {
  db close
  list [file exists test.db] [file exists test.db-wal] [file exists $shmpath]





} {1 0 0}

do_test walpersist-1.3 {
  sqlite3 db test.db
  db eval {SELECT length(a) FROM t1}
} {5000}
do_test walpersist-1.4 {
  list [file exists test.db] [file exists test.db-wal] [file exists $shmpath]
} {1 1 1}

do_test walpersist-1.5 {
  file_control_persist_wal db -1




} {0 0}

do_test walpersist-1.6 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.7 {
  file_control_persist_wal db -1
} {0 1}
do_test walpersist-1.8 {







>
|
|
|
>
>
>
>
>
|
>







>
|
|
>
>
>
>
|
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
    INSERT INTO t1 VALUES(randomblob(5000));
  }
  file exists test.db-wal
} {1}
do_test walpersist-1.1 {
  file exists $shmpath
} {1}
ifcapable enable_persist_wal {
  do_test walpersist-1.2-on {
    db close
    list [file exists test.db] [file exists test.db-wal] [file exists $shmpath]
  } {1 1 1}
} {
  do_test walpersist-1.2-off {
    db close
    list [file exists test.db] [file exists test.db-wal] [file exists $shmpath]
  } {1 0 0}
}
do_test walpersist-1.3 {
  sqlite3 db test.db
  db eval {SELECT length(a) FROM t1}
} {5000}
do_test walpersist-1.4 {
  list [file exists test.db] [file exists test.db-wal] [file exists $shmpath]
} {1 1 1}
ifcapable enable_persist_wal {
  do_test walpersist-1.5-on {
    file_control_persist_wal db -1
  } {0 1}
} {
  do_test walpersist-1.5-off {
    file_control_persist_wal db -1
  } {0 0}
}
do_test walpersist-1.6 {
  file_control_persist_wal db 1
} {0 1}
do_test walpersist-1.7 {
  file_control_persist_wal db -1
} {0 1}
do_test walpersist-1.8 {
Changes to test/walro.test.
149
150
151
152
153
154
155




156
157
158
159
160
161
162
    code1 { sqlite3 db test.db }
    csql1 { SELECT * FROM t1 }
  } {1 {unable to open database file}}

  # Also test that if the -shm file can be opened for read/write access,
  # it is not if readonly_shm=1 is present in the URI.
  do_test 1.3.2.1 {




    code1 { db close }
    code2 { db2 close }
    file exists $shmpath
  } {0}
  do_test 1.3.2.2 {
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
    csql1 { SELECT * FROM sqlite_master }







>
>
>
>







149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    code1 { sqlite3 db test.db }
    csql1 { SELECT * FROM t1 }
  } {1 {unable to open database file}}

  # Also test that if the -shm file can be opened for read/write access,
  # it is not if readonly_shm=1 is present in the URI.
  do_test 1.3.2.1 {
    ifcapable enable_persist_wal {
      code1 { file_control_persist_wal db 0 }
      code2 { file_control_persist_wal db2 0 }
    }
    code1 { db close }
    code2 { db2 close }
    file exists $shmpath
  } {0}
  do_test 1.3.2.2 {
    code1 { sqlite3 db file:test.db?readonly_shm=1 }
    csql1 { SELECT * FROM sqlite_master }