Index: src/os_unix.c ================================================================== --- src/os_unix.c +++ src/os_unix.c @@ -201,13 +201,11 @@ #endif #ifdef __QNXNTO__ int sectorSize; /* Device sector size */ int deviceCharacteristics; /* Precomputed device characteristics */ #endif -#if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ -#endif #if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__) unsigned fsFlags; /* cached details from statfs() */ #endif #if OS_VXWORKS struct vxworksFileId *pId; /* Unique file ID */ @@ -253,11 +251,12 @@ #endif #define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ #define UNIXFILE_DELETE 0x20 /* Delete on close */ #define UNIXFILE_URI 0x40 /* Filename might have query parameters */ #define UNIXFILE_NOLOCK 0x80 /* Do no file locking */ -#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings have been issued */ +#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() has issued warnings */ +#define UNIXFILE_DEFERRED 0x0200 /* File has not yet been opened */ /* ** Include code that is common to all os_*.c files */ #include "os_common.h" @@ -1355,13 +1354,18 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){ int rc = SQLITE_OK; int reserved = 0; unixFile *pFile = (unixFile*)id; + assert( pFile ); SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; ); - assert( pFile ); + if( pFile->ctrlFlags & UNIXFILE_DEFERRED ){ + *pResOut = 0; + return SQLITE_OK; + } + unixEnterMutex(); /* Because pFile->pInode is shared across threads */ /* Check if a thread in this process holds such a lock */ if( pFile->pInode->eFileLock>SHARED_LOCK ){ reserved = 1; @@ -1436,10 +1440,25 @@ }else{ rc = osFcntl(pFile->h, F_SETLK, pLock); } return rc; } + +static int unixOpen(sqlite3_vfs*, const char*, sqlite3_file*, int, int *); + +static int unixOpenAndLock(unixFile *pFile){ + sqlite3_file *id = (sqlite3_file*)pFile; + int eOrigLock = pFile->eFileLock; + int rc; + + assert( pFile->ctrlFlags & UNIXFILE_DEFERRED ); + rc = unixOpen(pFile->pVfs, pFile->zPath, id, pFile->openFlags, 0); + if( rc==SQLITE_OK && eOrigLock ){ + rc = id->pMethods->xLock(id, eOrigLock); + } + return rc; +} /* ** Lock the file with the lock specified by parameter eFileLock - one ** of the following: ** @@ -1521,13 +1540,33 @@ OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h, azFileLock(eFileLock))); return SQLITE_OK; } + if( pFile->ctrlFlags & UNIXFILE_DEFERRED ){ + const char *zPath = pFile->zPath; /* Full-path to database file */ + int eOrigLock; /* Current lock held on pFile */ + + assert( pFile->eFileLock==SHARED_LOCK || pFile->eFileLock==NO_LOCK ); + + /* If SQLite is requesting a SHARED lock and the database file does + ** not exist, return early without opening the file. */ + if( eFileLock==SHARED_LOCK && osAccess(zPath, F_OK) && errno==ENOENT ){ + pFile->eFileLock = SHARED_LOCK; + return SQLITE_OK; + } + + /* Or, if the database file has been created or a write lock is + ** requested, open the database file now. */ + rc = unixOpenAndLock(pFile); + if( rc!=SQLITE_OK ) return rc; + } + assert( (pFile->ctrlFlags & UNIXFILE_DEFERRED)==0 ); + /* Make sure the locking sequence is correct. ** (1) We never move from unlocked to anything higher than shared lock. - ** (2) SQLite never explicitly requests a pendig lock. + ** (2) SQLite never explicitly requests a pending lock. ** (3) A shared lock is always held when a reserve lock is requested. */ assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK ); assert( eFileLock!=PENDING_LOCK ); assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK ); @@ -1724,10 +1763,11 @@ assert( eFileLock<=SHARED_LOCK ); if( pFile->eFileLock<=eFileLock ){ return SQLITE_OK; } unixEnterMutex(); + if( pFile->ctrlFlags & UNIXFILE_DEFERRED ) goto end_unlock; pInode = pFile->pInode; assert( pInode->nShared!=0 ); if( pFile->eFileLock>SHARED_LOCK ){ assert( pInode->eFileLock==pFile->eFileLock ); @@ -1930,23 +1970,27 @@ unixFile *pFile = (unixFile *)id; verifyDbFile(pFile); unixUnlock(id, NO_LOCK); unixEnterMutex(); - /* unixFile.pInode is always valid here. Otherwise, a different close - ** routine (e.g. nolockClose()) would be called instead. - */ - assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 ); - if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){ - /* If there are outstanding locks, do not actually close the file just - ** yet because that would clear those locks. Instead, add the file - ** descriptor to pInode->pUnused list. It will be automatically closed - ** when the last lock is cleared. - */ - setPendingFd(pFile); - } - releaseInodeInfo(pFile); + /* unixFile.pInode may be NULL here if the file was never opened. + */ + assert( pFile->pInode==0 + || pFile->pInode->nLock>0 + || pFile->pInode->bProcessLock==0 + ); + if( pFile->pInode ){ + if( pFile->pInode->nLock ){ + /* If there are outstanding locks, do not actually close the file just + ** yet because that would clear those locks. Instead, add the file + ** descriptor to pInode->pUnused list. It will be automatically closed + ** when the last lock is cleared. + */ + setPendingFd(pFile); + } + releaseInodeInfo(pFile); + } rc = closeUnixFile(id); unixLeaveMutex(); return rc; } @@ -3171,10 +3215,24 @@ || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #endif + if( pFile->ctrlFlags & UNIXFILE_DEFERRED ){ + int rc; + if( osAccess(pFile->zPath, F_OK) && errno==ENOENT ){ + memset(pBuf, 0, amt); + rc = SQLITE_IOERR_SHORT_READ; + }else{ + rc = unixOpen(pFile->pVfs, pFile->zPath, id, pFile->openFlags, 0); + } + if( rc!=SQLITE_OK ){ + return rc; + } + } + assert( (pFile->ctrlFlags & UNIXFILE_DEFERRED)==0 ); + #if SQLITE_MAX_MMAP_SIZE>0 /* Deal with as much of this read request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offsetmmapSize ){ if( offset+amt <= pFile->mmapSize ){ @@ -3274,10 +3332,19 @@ ){ unixFile *pFile = (unixFile*)id; int wrote = 0; assert( id ); assert( amt>0 ); + + /* SQLite never actually calls xWrite on an empty file before obtaining + ** a RESERVED lock on it. So the following condition is never true if + ** the VFS is being used directly by SQLite. But it may be if this module + ** is being used in some other way. By the multiplexor VFS, for example. */ + if( pFile->ctrlFlags & UNIXFILE_DEFERRED ){ + int rc = unixOpenAndLock(pFile); + if( rc!=SQLITE_OK ) return rc; + } /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pUnused==0 @@ -3623,14 +3690,23 @@ /* ** Determine the current size of a file in bytes */ static int unixFileSize(sqlite3_file *id, i64 *pSize){ + unixFile *pFile = (unixFile*)id; int rc; struct stat buf; assert( id ); - rc = osFstat(((unixFile*)id)->h, &buf); + if( pFile->ctrlFlags & UNIXFILE_DEFERRED ){ + rc = osStat(pFile->zPath, &buf); + if( rc && errno==ENOENT ){ + rc = 0; + buf.st_size = 0; + } + }else{ + rc = osFstat(pFile->h, &buf); + } SimulateIOError( rc=1 ); if( rc!=0 ){ ((unixFile*)id)->lastErrno = errno; return SQLITE_IOERR_FSTAT; } @@ -3641,11 +3717,10 @@ ** in the OS-X msdos filesystem. In order to avoid problems with upper ** layers, we need to report this file size as zero even though it is ** really 1. Ticket #3260. */ if( *pSize==1 ) *pSize = 0; - return SQLITE_OK; } #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) @@ -5174,18 +5249,11 @@ OSTRACE(("OPEN %-3d %s\n", h, zFilename)); pNew->h = h; pNew->pVfs = pVfs; pNew->zPath = zFilename; - pNew->ctrlFlags = (u8)ctrlFlags; -#if SQLITE_MAX_MMAP_SIZE>0 - pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap; -#endif - if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), - "psow", SQLITE_POWERSAFE_OVERWRITE) ){ - pNew->ctrlFlags |= UNIXFILE_PSOW; - } + pNew->ctrlFlags = (unsigned short)ctrlFlags; if( strcmp(pVfs->zName,"unix-excl")==0 ){ pNew->ctrlFlags |= UNIXFILE_EXCL; } #if OS_VXWORKS @@ -5320,11 +5388,10 @@ #endif if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); }else{ pNew->pMethod = pLockingStyle; - OpenCounter(+1); verifyDbFile(pNew); } return rc; } @@ -5577,11 +5644,11 @@ int fd = -1; /* File descriptor returned by open() */ int openFlags = 0; /* Flags to pass to open() */ int eType = flags&0xFFFFFF00; /* Type of file to open */ int noLock; /* True to omit locking primitives */ int rc = SQLITE_OK; /* Function Return Code */ - int ctrlFlags = 0; /* UNIXFILE_* flags */ + int ctrlFlags; /* UNIXFILE_* flags */ int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); int isCreate = (flags & SQLITE_OPEN_CREATE); int isReadonly = (flags & SQLITE_OPEN_READONLY); @@ -5606,10 +5673,15 @@ /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. */ char zTmpname[MAX_PATHNAME+2]; const char *zName = zPath; + + assert( p->pInode==0 && (p->h==-1 || p->h==0) ); + p->ctrlFlags &= ~UNIXFILE_DEFERRED; + p->eFileLock = NO_LOCK; + ctrlFlags = p->ctrlFlags; /* Check the following statements are true: ** ** (a) Exactly one of the READWRITE and READONLY flags must be set, and ** (b) if CREATE is set, then READWRITE must also be set, and @@ -5643,11 +5715,10 @@ if( randomnessPid!=getpid() ){ randomnessPid = getpid(); sqlite3_randomness(0,0); } - memset(p, 0, sizeof(unixFile)); if( eType==SQLITE_OPEN_MAIN_DB ){ UnixUnusedFd *pUnused; pUnused = findReusableFd(zName, flags); if( pUnused ){ @@ -5816,14 +5887,73 @@ rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); open_finished: if( rc!=SQLITE_OK ){ sqlite3_free(p->pUnused); + p->pUnused = 0; + } + return rc; +} + +static int unixOpenDeferred( + sqlite3_vfs *pVfs, /* The VFS for which this is the xOpen method */ + const char *zPath, /* Pathname of file to be opened */ + sqlite3_file *pFile, /* The file descriptor to be filled in */ + int flags, /* Input flags to control the opening */ + int *pOutFlags /* Output flags returned to SQLite core */ +){ + const int mask1 = SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_READWRITE + | SQLITE_OPEN_CREATE; + const int mask2 = SQLITE_OPEN_READONLY | SQLITE_OPEN_DELETEONCLOSE + | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_AUTOPROXY; + + int rc; /* Return code */ + unixFile *p = (unixFile*)pFile; /* File object to populate */ + const char *zUri = (flags & UNIXFILE_URI) ? zPath : 0; + + /* Zero the file object */ + memset(p, 0, sizeof(unixFile)); + if( sqlite3_uri_boolean(zUri, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ + p->ctrlFlags |= UNIXFILE_PSOW; + } +#if SQLITE_MAX_MMAP_SIZE>0 + p->mmapSizeMax = sqlite3GlobalConfig.szMmap; +#endif + + /* If all the flags in mask1 are set, and all the flags in mask2 are + ** clear, the file does not exist but the directory does and is + ** writable, then this is a deferred open. */ + if( zPath && (flags & (mask1 | mask2))==mask1 ){ + int posixrc; + posixrc = osAccess(zPath, F_OK); + if( posixrc && errno==ENOENT ){ + char zDirname[MAX_PATHNAME+1]; + int i; + for(i=(int)strlen(zPath); i>1 && zPath[i]!='/'; i--); + memcpy(zDirname, zPath, i); + zDirname[i] = '\0'; + posixrc = osAccess(zDirname, W_OK); + if( posixrc==0 ){ + p->pMethod = (**(finder_type*)pVfs->pAppData)(0, 0); + if( p->pMethod->xLock==unixLock ){ + p->pVfs = pVfs; + p->h = -1; + p->ctrlFlags |= UNIXFILE_DEFERRED; + p->openFlags = flags; + p->zPath = zPath; + if( pOutFlags ) *pOutFlags = flags; + OpenCounter(+1); + return SQLITE_OK; + } + } + } } + + rc = unixOpen(pVfs, zPath, pFile, flags, pOutFlags); + OpenCounter( rc==SQLITE_OK ); return rc; } - /* ** Delete the file at zPath. If the dirSync argument is true, fsync() ** the directory after deleting the file. */ @@ -7374,11 +7504,11 @@ sizeof(unixFile), /* szOsFile */ \ MAX_PATHNAME, /* mxPathname */ \ 0, /* pNext */ \ VFSNAME, /* zName */ \ (void*)&FINDER, /* pAppData */ \ - unixOpen, /* xOpen */ \ + unixOpenDeferred, /* xOpen */ \ unixDelete, /* xDelete */ \ unixAccess, /* xAccess */ \ unixFullPathname, /* xFullPathname */ \ unixDlOpen, /* xDlOpen */ \ unixDlError, /* xDlError */ \ Index: src/test2.c ================================================================== --- src/test2.c +++ src/test2.c @@ -532,11 +532,14 @@ sqlite3_free(zFile); return TCL_ERROR; } offset = n; offset *= 1024*1024; + sqlite3OsLock(fd, SHARED_LOCK); + sqlite3OsLock(fd, EXCLUSIVE_LOCK); rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset); + sqlite3OsUnlock(fd, NO_LOCK); sqlite3OsCloseFree(fd); sqlite3_free(zFile); if( rc ){ Tcl_AppendResult(interp, "write failed: ", sqlite3ErrName(rc), 0); return TCL_ERROR; Index: test/backup.test ================================================================== --- test/backup.test +++ test/backup.test @@ -331,18 +331,18 @@ catch { forcedelete test2.db } sqlite3 db test.db set iTab 1 db eval { PRAGMA page_size = 512 } - while {[file size test.db] <= $::sqlite_pending_byte} { + while {[file_size test.db] <= $::sqlite_pending_byte} { db eval "CREATE TABLE t${iTab}(a, b, c)" incr iTab } sqlite3 db2 test2.db db2 eval { PRAGMA page_size = 4096 } - while {[file size test2.db] < $::sqlite_pending_byte} { + while {[file_size test2.db] < $::sqlite_pending_byte} { db2 eval "CREATE TABLE t${iTab}(a, b, c)" incr iTab } sqlite3_backup B db2 main db main Index: test/backup4.test ================================================================== --- test/backup4.test +++ test/backup4.test @@ -70,11 +70,11 @@ db1 backup test.db db1 close file size test.db } {1024} -do_test 2.4 { file size test.db2 } 0 +do_test 2.4 { file_size test.db2 } 0 db close forcedelete test.db forcedelete test.db2 sqlite3 db test.db @@ -96,8 +96,8 @@ db1 backup test.db db1 close file size test.db } {1024} -do_test 3.4 { file size test.db2 } 0 +do_test 3.4 { file_size test.db2 } 0 finish_test Index: test/capi3e.test ================================================================== --- test/capi3e.test +++ test/capi3e.test @@ -68,13 +68,16 @@ do_test capi3e-1.1.$i { set db2 [sqlite3_open $name {}] sqlite3_errcode $db2 } {SQLITE_OK} do_test capi3e-1.2.$i { + sqlite3_exec $db2 { CREATE TABLE t1(x) } + } {0 {}} + do_test capi3e-1.3.$i { sqlite3_close $db2 } {SQLITE_OK} - do_test capi3e-1.3.$i { + do_test capi3e-1.4.$i { file isfile $name } {1} } ifcapable {utf16} { Index: test/e_uri.test ================================================================== --- test/e_uri.test +++ test/e_uri.test @@ -62,30 +62,34 @@ sqlite3_shutdown sqlite3_config_uri 0 do_test 1.1 { forcedelete file:test.db test.db set DB [sqlite3_open_v2 file:test.db [concat $flags SQLITE_OPEN_URI] ""] + sqlite3_exec $DB {CREATE TABLE t1(x)} list [file exists file:test.db] [file exists test.db] } {0 1} do_test 1.2 { forcedelete file:test.db2 test.db2 set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy] sqlite3_step $STMT sqlite3_finalize $STMT + sqlite3_exec $DB {CREATE TABLE aux.t1(x)} list [file exists file:test.db2] [file exists test.db2] } {0 1} sqlite3_close $DB do_test 1.3 { forcedelete file:test.db test.db set DB [sqlite3_open_v2 file:test.db [concat $flags] ""] + sqlite3_exec $DB {CREATE TABLE t1(x)} list [file exists file:test.db] [file exists test.db] } {1 0} do_test 1.4 { forcedelete file:test.db2 test.db2 set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy] sqlite3_step $STMT sqlite3_finalize $STMT + sqlite3_exec $DB {CREATE TABLE aux.t1(x)} list [file exists file:test.db2] [file exists test.db2] } {1 0} sqlite3_close $DB # Tests with SQLITE_CONFIG_URI configured to true. URI intepretation is @@ -94,30 +98,34 @@ sqlite3_shutdown sqlite3_config_uri 1 do_test 1.5 { forcedelete file:test.db test.db set DB [sqlite3_open_v2 file:test.db [concat $flags SQLITE_OPEN_URI] ""] + sqlite3_exec $DB {CREATE TABLE t1(x)} list [file exists file:test.db] [file exists test.db] } {0 1} do_test 1.6 { forcedelete file:test.db2 test.db2 set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy] sqlite3_step $STMT sqlite3_finalize $STMT + sqlite3_exec $DB {CREATE TABLE aux.t1(x)} list [file exists file:test.db2] [file exists test.db2] } {0 1} sqlite3_close $DB do_test 1.7 { forcedelete file:test.db test.db set DB [sqlite3_open_v2 file:test.db [concat $flags] ""] + sqlite3_exec $DB {CREATE TABLE t1(x)} list [file exists file:test.db] [file exists test.db] } {0 1} do_test 1.8 { forcedelete file:test.db2 test.db2 set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy] sqlite3_step $STMT sqlite3_finalize $STMT + sqlite3_exec $DB {CREATE TABLE aux.t1(x)} list [file exists file:test.db2] [file exists test.db2] } {0 1} sqlite3_close $DB } @@ -312,10 +320,11 @@ # mode parameter that is less restrictive than that specified by the # flags passed in the third parameter to sqlite3_open_v2(). # forcedelete test.db sqlite3 db test.db +db eval {CREATE TABLE t1(x)} db close foreach {tn uri flags error} { 1 {file:test.db?mode=ro} ro {not an error} 2 {file:test.db?mode=ro} rw {not an error} 3 {file:test.db?mode=ro} rwc {not an error} @@ -329,11 +338,11 @@ 9 {file:test.db?mode=rwc} rwc {not an error} } { set f(ro) [list SQLITE_OPEN_READONLY SQLITE_OPEN_URI] set f(rw) [list SQLITE_OPEN_READWRITE SQLITE_OPEN_URI] set f(rwc) [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI] - +breakpoint set DB [sqlite3_open_v2 $uri $f($flags) ""] set e [sqlite3_errmsg $DB] sqlite3_close $DB do_test 9.$tn { set e } $error Index: test/exclusive2.test ================================================================== --- test/exclusive2.test +++ test/exclusive2.test @@ -67,22 +67,24 @@ if {$needClose} {close $fd} return $ret } proc readPagerChangeCounter {filename} { - set fd [open $filename RDONLY] - fconfigure $fd -translation binary -encoding binary - - seek $fd 24 - foreach {a b c d} [list 0 0 0 0] {} - binary scan [read $fd 4] cccc a b c d - set ret [expr ($a&0x000000FF)<<24] - incr ret [expr ($b&0x000000FF)<<16] - incr ret [expr ($c&0x000000FF)<<8] - incr ret [expr ($d&0x000000FF)<<0] - - close $fd + if {[file exists $filename]} { + set fd [open $filename RDONLY] + fconfigure $fd -translation binary -encoding binary + seek $fd 24 + foreach {a b c d} [list 0 0 0 0] {} + binary scan [read $fd 4] cccc a b c d + set ret [expr ($a&0x000000FF)<<24] + incr ret [expr ($b&0x000000FF)<<16] + incr ret [expr ($c&0x000000FF)<<8] + incr ret [expr ($d&0x000000FF)<<0] + close $fd + } else { + set ret 0 + } return $ret } proc t1sig {{db db}} { Index: test/incrvacuum.test ================================================================== --- test/incrvacuum.test +++ test/incrvacuum.test @@ -36,11 +36,11 @@ } $sqlite_options(default_autovacuum) do_test incrvacuum-1.2.0 { # File size is sometimes 1 instead of 0 due to the hack we put in # to work around ticket #3260. Search for comments on #3260 in # os_unix.c. - expr {[file size test.db] > 1} + expr {[file_size test.db] > 1} } {0} do_test incrvacuum-1.2 { # This command will create the database. execsql { pragma auto_vacuum = 'full'; @@ -698,11 +698,11 @@ do_test incrvacuum-13.1 { # File size is sometimes 1 instead of 0 due to the hack we put in # to work around ticket #3260. Search for comments on #3260 in # os_unix.c. - expr {[file size test.db]>1} + expr {[file_size test.db]>1} } {0} do_test incrvacuum-13.2 { set ::STMT [sqlite3_prepare $::DB {PRAGMA auto_vacuum = 2} -1 DUMMY] execsql { PRAGMA auto_vacuum = none; Index: test/io.test ================================================================== --- test/io.test +++ test/io.test @@ -389,11 +389,11 @@ db eval { PRAGMA auto_vacuum=OFF; } # File size might be 1 due to the hack to work around ticket #3260. # Search for #3260 in os_unix.c for additional information. - expr {[file size test.db]>1} + expr {[file_size test.db]>1} } {0} do_test io-3.2 { execsql { CREATE TABLE abc(a, b) } nSync execsql { Index: test/pager1.test ================================================================== --- test/pager1.test +++ test/pager1.test @@ -1371,11 +1371,11 @@ } db2 sqlite3_backup B db2 main db main list [B step 10000] [B finish] } {SQLITE_DONE SQLITE_OK} do_test pager1-9.4.2 { - list [file size test.db2] [file size test.db] + list [file_size test.db2] [file_size test.db] } {1024 0} db2 close #------------------------------------------------------------------------- # Test that regardless of the value returned by xSectorSize(), the Index: test/permutations.test ================================================================== --- test/permutations.test +++ test/permutations.test @@ -133,11 +133,11 @@ test_suite "veryquick" -prefix "" -description { "Very" quick test suite. Runs in less than 5 minutes on a workstation. This test suite is the same as the "quick" tests, except that some files that test malloc and IO errors are omitted. } -files [ - test_set $allquicktests -exclude *malloc* *ioerr* *fault* + test_set $allquicktests -exclude *malloc* *ioerr* *fault* ] test_suite "mmap" -prefix "mm-" -description { Similar to veryquick. Except with memory mapping disabled. } -presql { Index: test/syscall.test ================================================================== --- test/syscall.test +++ test/syscall.test @@ -234,13 +234,14 @@ # catch { db close } forcedelete test.db test.db2 do_test 8.1 { + close [open test.db w] sqlite3 db test.db file_control_chunksize_test db main 4096 - file size test.db + file_size test.db } {0} foreach {tn hint size} { 1 1000 4096 2 1000 4096 3 3000 4096 @@ -247,17 +248,18 @@ 4 4096 4096 5 4197 8192 } { do_test 8.2.$tn { file_control_sizehint_test db main $hint - file size test.db + file_size test.db } $size } do_test 8.3 { db close forcedelete test.db test.db2 + close [open test.db w] sqlite3 db test.db file_control_chunksize_test db main 16 file size test.db } {0} foreach {tn hint size} { Index: test/tester.tcl ================================================================== --- test/tester.tcl +++ test/tester.tcl @@ -182,10 +182,20 @@ } proc forcecopy {from to} { do_copy_file true $from $to } + +# If file $zFile exists in the file system, return its size in bytes. +# Otherwise, return zero. +proc file_size {zFile} { + if {[file exists $zFile]} { + return [file size $zFile] + } + return 0 +} + proc do_copy_file {force from to} { set nRetry [getFileRetries] ;# Maximum number of retries. set nDelay [getFileRetryDelay] ;# Delay in ms before retrying. Index: test/tkt4018.test ================================================================== --- test/tkt4018.test +++ test/tkt4018.test @@ -44,10 +44,11 @@ # The database is locked by connection [db]. Open and close a second # connection to test.db 10000 times. If file-descriptors are not being # reused, then the process will quickly exceed its maximum number of # file descriptors (1024 by default on linux). +breakpoint do_test tkt4018-1.2 { for {set i 0} {$i < 10000} {incr i} { sqlite3 db2 test.db db2 close } Index: test/uri.test ================================================================== --- test/uri.test +++ test/uri.test @@ -74,17 +74,19 @@ if {[file isdir $file]} {error "$file is a directory"} forcedelete $file do_test 1.$tn.1 { file exists $file } 0 set DB [sqlite3_open $uri] + sqlite3_exec $DB {CREATE TABLE t1(x)} do_test 1.$tn.2 { file exists $file } 1 sqlite3_close $DB forcedelete $file do_test 1.$tn.3 { file exists $file } 0 sqlite3 db xxx.db catchsql { ATTACH $uri AS aux } + db eval {CREATE TABLE aux.t1(x)} do_test 1.$tn.4 { file exists $file } 1 db close } #------------------------------------------------------------------------- Index: test/wal4.test ================================================================== --- test/wal4.test +++ test/wal4.test @@ -54,11 +54,11 @@ # a fault was injected. Test these assertions: # if { $testrc==0 && [file exists test.db-wal] } { error "Wal file was not deleted" } - if { [file size test.db]!=0 } { - error "Db file grew to [file size test.db] bytes" + if { [file_size test.db]!=0 } { + error "Db file grew to [file_size test.db] bytes" } } finish_test