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: |
654792941011c96db879f6b779e99b1c |
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
Changes to Makefile.in.
︙ | ︙ | |||
53 54 55 56 57 58 59 | # The library that programs using readline() must link against. # LIBREADLINE = @TARGET_READLINE_LIBS@ # Should the database engine be compiled threadsafe # | | | 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 | # 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 # | | | 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 | 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) \ | | | < | 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 | $(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: | | | | | | | 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 | 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 */ | | | 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 | unixFile *pFile = (unixFile*)id; int eFileLock = pFile->eFileLock; int rc = SQLITE_OK; if( eFileLock<eTargetFileLock ){ rc = pFile->pMethod->xLock(id, SQLITE_LOCK_SHARED); } | | | 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 | */ 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) ){ | > > > > | | 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 | /* 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 ){ | | | | | 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 | 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); | | | | 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 | ){ 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) ){ | | | 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 | #else rc = SQLITE_IOERR_UNLOCK; #endif } if( rc ){ if( IS_LOCK_ERROR(rc) ){ | | | 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 | lock.l_len = SHARED_SIZE; } if( unixFileLock(pFile, &lock, 0) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( rc!=SQLITE_BUSY ){ | | | 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 | tErrno = errno; #if OSLOCKING_CHECK_BUSY_IOERR rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); #else rc = SQLITE_IOERR_UNLOCK; #endif if( IS_LOCK_ERROR(rc) ){ | | | | | 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 | /* 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; | | | | | | 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 | 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) ){ | | | | 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 | */ 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 ){ | | | 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 | /* 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) ){ | | | 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 | #if OSLOCKING_CHECK_BUSY_IOERR rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); #else rc = SQLITE_IOERR_UNLOCK; #endif } if( IS_LOCK_ERROR(rc) ){ | | | 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 | /* 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) ){ | | | | 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 | /* 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) ){ | | | 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 | 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); | | | 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 | } /* no, really unlock. */ if ( sem_post(pSem)==-1 ) { int rc, tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(rc) ){ | | | 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 | #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) ){ | | | 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 | 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) ) { | | | 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 | 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 ){ | | | | | 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 | 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{ | | | 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 | 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 ){ | | | | | 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 | SimulateDiskfullError(( wrote=0, amt=1 )); if( amt>0 ){ if( wrote<0 && pFile->lastErrno!=ENOSPC ){ /* lastErrno set by seekAndWrite */ return SQLITE_IOERR_WRITE; }else{ | | | 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 | SimulateDiskfullError( return SQLITE_FULL ); assert( pFile ); OSTRACE(("SYNC %-3d\n", pFile->h)); rc = full_fsync(pFile->h, isFullsync, isDataOnly); SimulateIOError( rc=1 ); if( rc ){ | | | | 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 | */ if( pFile->szChunk>0 ){ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } rc = robust_ftruncate(pFile->h, (off_t)nByte); if( rc ){ | | | 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 | 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 ){ | | | 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 | ** 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) ){ | | | 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 | 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; | | > > > | 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 | if( fcopyfile(srcWalFD, dstWalFD, s, COPYFILE_ALL) ){ int err=errno; switch(err) { case ENOMEM: rc = SQLITE_NOMEM; break; default: | | | 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 | if( fcopyfile(pSrcFile->h, pFile->h, s, COPYFILE_ALL) ){ int err=errno; switch(err) { case ENOMEM: rc = SQLITE_NOMEM; break; default: | | | 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 | if( pShmNode->mutex==0 ){ rc = SQLITE_NOMEM; goto shm_open_err; } if( pInode->bProcessLock==0 ){ int openFlags = O_RDWR | O_CREAT; | | > > > > > | 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 | 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; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > > > > | 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 | 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: | > > > | | | > > > > > > > | 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 | ** 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 */ | | > > > | > | > | 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 | if( isDelete ){ #if OS_VXWORKS zPath = zName; #else osUnlink(zName); #endif } | | | > > > > > | 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 | * 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) ){ | | | | 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 | 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 ){ | | | | 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 | 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) ){ | | | 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 | ** 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) /* | > > | | 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 | 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 | > > | | > > | > > > | > > > | > | 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 | }] ifcapable !wal { set skipwaltests 1 } if {![wal_is_ok]} { set skipwaltests 1 } if {!$skipwaltests} { db close forcedelete 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 | 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 { | > | | | > > | | | | | | > | 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 | 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 | > | | | > | 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 | 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 | > | | | | | | | > | 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 | 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. | | > > | 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 | 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} | > > | > | 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 | 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 } | > > | | 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 | INSERT INTO t1 VALUES(randomblob(5000)); } file exists test.db-wal } {1} do_test walpersist-1.1 { file exists $shmpath } {1} | > | | | > > > > > | > > | | > > > > | > | 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 } |
︙ | ︙ |