Modify the OS layer so that I/O routines are called through a virtual function
table. The os_test.c module has been replaced by test6.c. The crash tests are busted now and need to be fixed. (CVS 2785) FossilOrigin-Name: 1f69aec285dd8e26bd739d5e44bb50fe03a9682a
This commit is contained in:
parent
aa2289f89c
commit
9c06c95309
10
Makefile.in
10
Makefile.in
@ -189,6 +189,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test3.c \
|
||||
$(TOP)/src/test4.c \
|
||||
$(TOP)/src/test5.c \
|
||||
$(TOP)/src/test6.c \
|
||||
$(TOP)/src/utf.c \
|
||||
$(TOP)/src/util.c \
|
||||
$(TOP)/src/vdbe.c \
|
||||
@ -425,15 +426,8 @@ testfixture$(TEXE): $(TOP)/src/tclsqlite.c libsqlite3.la $(TESTSRC)
|
||||
-o testfixture $(TESTSRC) $(TOP)/src/tclsqlite.c \
|
||||
libsqlite3.la $(LIBTCL)
|
||||
|
||||
crashtest$(TEXE): $(TOP)/src/tclsqlite.c libsqlite3.la $(TESTSRC) $(TOP)/src/os_test.c
|
||||
$(LTLINK) -DOS_TEST=1 -DTCLSH=1 -DSQLITE_TEST=1 \
|
||||
-o crashtest \
|
||||
$(TESTSRC) $(TOP)/src/os_test.c $(TOP)/src/tclsqlite.c \
|
||||
libsqlite3.la $(LIBTCL)
|
||||
|
||||
|
||||
|
||||
fulltest: testfixture$(TEXE) sqlite3$(TEXE) crashtest$(TEXE)
|
||||
fulltest: testfixture$(TEXE) sqlite3$(TEXE)
|
||||
./testfixture $(TOP)/test/all.test
|
||||
|
||||
test: testfixture$(TEXE) sqlite3$(TEXE)
|
||||
|
11
main.mk
11
main.mk
@ -131,6 +131,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test3.c \
|
||||
$(TOP)/src/test4.c \
|
||||
$(TOP)/src/test5.c \
|
||||
$(TOP)/src/test6.c \
|
||||
$(TOP)/src/utf.c \
|
||||
$(TOP)/src/util.c \
|
||||
$(TOP)/src/vdbe.c \
|
||||
@ -356,13 +357,7 @@ testfixture$(EXE): $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC)
|
||||
$(TESTSRC) $(TOP)/src/tclsqlite.c \
|
||||
libsqlite3.a $(LIBTCL) $(THREADLIB)
|
||||
|
||||
crashtest: $(TOP)/src/tclsqlite.c libsqlite3.a $(TESTSRC) $(TOP)/src/os_test.c
|
||||
$(TCCX) $(TCL_FLAGS) -DOS_TEST=1 -DTCLSH=1 -DSQLITE_TEST=1 \
|
||||
-o crashtest \
|
||||
$(TESTSRC) $(TOP)/src/os_test.c $(TOP)/src/tclsqlite.c \
|
||||
libsqlite3.a $(LIBTCL) $(THREADLIB)
|
||||
|
||||
fulltest: testfixture$(EXE) sqlite3$(EXE) crashtest
|
||||
fulltest: testfixture$(EXE) sqlite3$(EXE)
|
||||
./testfixture$(EXE) $(TOP)/test/all.test
|
||||
|
||||
test: testfixture$(EXE) sqlite3$(EXE)
|
||||
@ -557,7 +552,7 @@ install: sqlite3 libsqlite3.a sqlite3.h
|
||||
mv sqlite3.h /usr/include
|
||||
|
||||
clean:
|
||||
rm -f *.o sqlite3 libsqlite3.a sqlite3.h opcodes.* crashtest
|
||||
rm -f *.o sqlite3 libsqlite3.a sqlite3.h opcodes.*
|
||||
rm -f lemon lempar.c parse.* sqlite*.tar.gz mkkeywordhash keywordhash.h
|
||||
rm -f $(PUBLISH)
|
||||
rm -f *.da *.bb *.bbg gmon.out
|
||||
|
43
manifest
43
manifest
@ -1,6 +1,6 @@
|
||||
C Ensure\sa\slow\ssystem\slimit\son\sthe\snumber\sof\sopen\sfiles\sdoes\snot\scause\smanydb.test\sto\sfail.\s(CVS\s2784)
|
||||
D 2005-11-25T10:55:58
|
||||
F Makefile.in 7bed51530f32af7fe1945261c388d80998b39a12
|
||||
C Modify\sthe\sOS\slayer\sso\sthat\sI/O\sroutines\sare\scalled\sthrough\sa\svirtual\sfunction\ntable.\s\sThe\sos_test.c\smodule\shas\sbeen\sreplaced\sby\stest6.c.\s\sThe\scrash\stests\nare\sbusted\snow\sand\sneed\sto\sbe\sfixed.\s(CVS\s2785)
|
||||
D 2005-11-26T00:25:01
|
||||
F Makefile.in 28a2772cd9e03ba758c2a052813092cdb9da73bf
|
||||
F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
|
||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||
F VERSION b818cce180263e590a00ad4509a713892c3eecea
|
||||
@ -19,7 +19,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
|
||||
F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826
|
||||
F main.mk c2c2f377be833dff5ec17840b9329d561ceec280
|
||||
F main.mk 1cf8c00ee4439d3332a2da771fe168ed8420c2d7
|
||||
F mkdll.sh 5ec23622515d5bf8969404e80cfb5e220ddf0512
|
||||
F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d
|
||||
F mkopcodeh.awk 071dbba4eaf56c8d643baf4604a043af35683316
|
||||
@ -50,18 +50,18 @@ F src/insert.c da031c3ed8e1675fac891990095d277c2ba6e205
|
||||
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
|
||||
F src/main.c 97bb830cdbd378d1f87469618471f52d9d263d09
|
||||
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
|
||||
F src/os.h c51f2747f7bd1840447e2c7d26db749604626814
|
||||
F src/os.h 64564ddc5b70f8968d1df5039810a2e68cebe769
|
||||
F src/os_common.h d74a11728ad2444b6b695b94c28c06881f049e49
|
||||
F src/os_test.c 49833426101f99aee4bb5f6a44b7c4b2029fda1c
|
||||
F src/os_test.h 903c93554c23d88f34f667f1979e4a1cee792af3
|
||||
F src/os_unix.c 1c51efc1755b5413dc69c8500b78646babd8065d
|
||||
F src/os_unix.c 57f47fd9172991550b2af15b18d8cc9ccb90d307
|
||||
F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
|
||||
F src/os_win.c fbccc85e7011174068c27d54256746321a1f0059
|
||||
F src/os_win.c 5d282b4fb2afdeefd0857357206510e72192302c
|
||||
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
|
||||
F src/pager.c ca23cdff9e67a8e826e4796c60f06db6aab69b72
|
||||
F src/pager.c 561657a20ecbc5fa4c8e1fcfe019006553fd39a1
|
||||
F src/pager.h e7b41ce8e7b5f629d456708b7ad9a8c8ede37140
|
||||
F src/parse.y e4d57c2fd5cc02f19822ec41f6dc2bfc9bc85609
|
||||
F src/pragma.c b40189967155a522433b8470f363192a927ba22c
|
||||
F src/pragma.c e278b3f722379ab9d630a1569ac05f586f01f4db
|
||||
F src/prepare.c fc098db25d2a121affb08686cf04833fd50452d4
|
||||
F src/printf.c 3ea3a17d25d7ac498efc18007c70371a42c968f8
|
||||
F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4
|
||||
@ -70,23 +70,24 @@ F src/shell.c 3596c1e559b82663057940d19ba533ad421c7dd3
|
||||
F src/sqlite.h.in 8e648e1f386e4509f2f96c09ded7c07b0df0c9a2
|
||||
F src/sqliteInt.h 4148c9778e350014c2e27b332d7a2ef7278fe62e
|
||||
F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
|
||||
F src/tclsqlite.c 4f274fae3d4a1863451a553dd8e5015747a5d91d
|
||||
F src/test1.c 7a4e6f08ed6f7ce1e82949cb27954ab676f6e048
|
||||
F src/test2.c d55861d8ba5a8b434544da366ba6efe206e1ec97
|
||||
F src/tclsqlite.c a497c3adfd2c85da6a934331ec0041e47884fbcb
|
||||
F src/test1.c 415c9c4571bf9ecbec3a7bba3c4338efd83fc137
|
||||
F src/test2.c 360cfa7fe17a4fe67f6d19699cd6d59fca4ff09f
|
||||
F src/test3.c f4e6a16a602091696619a1171bda25c0e3df49f7
|
||||
F src/test4.c a8fd681e139e1c61f22a77d07fc3a99cb28fff3f
|
||||
F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
|
||||
F src/test6.c d86ca78abd3c37149add00efc6538128e776714c
|
||||
F src/tokenize.c bdb79702217af49eba44c2a3b4f5fc7bd9ed2917
|
||||
F src/trigger.c aea0283a3ef729a3e9c8dc5dc1a11c9fcc0a12a7
|
||||
F src/update.c fec7665138ccf2a2133f11dcd24c1134c6b33526
|
||||
F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c
|
||||
F src/util.c 48fecbbef4391d102a23096d32f0d74173428406
|
||||
F src/vacuum.c baae8681282c7a03900043043dc7ce07d43b5a1e
|
||||
F src/vdbe.c f90a0fff5dac2ae11f880fb54e78132640199c44
|
||||
F src/vacuum.c 3a9d801b642a2004e8a99efa8d19ceef3f79d8df
|
||||
F src/vdbe.c 88a85e681522e82e14c8d08adacccbe4e96dd1c9
|
||||
F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
|
||||
F src/vdbeInt.h 0055c37eccbf3a189fd893a90f8eb6a5fa60c871
|
||||
F src/vdbeapi.c 85bbe1d0243a89655433d60711b4bd71979b59cd
|
||||
F src/vdbeaux.c eb5f7185a4a714b352c0b6dc804ad3180e03ec06
|
||||
F src/vdbeaux.c 3dca9c04c07dda17f0cb06b3a552e1e23106232f
|
||||
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
|
||||
F src/vdbemem.c cd9609c1e7f71ec76d9840c84c3a57ebfa6539cf
|
||||
F src/where.c 9c260db859047a44fe8219716ee5f0d2bd647420
|
||||
@ -135,7 +136,7 @@ F test/collate6.test 6c9470d1606ee3e564675b229653e320c49ec638
|
||||
F test/conflict.test bc7b81670abfd6ca51cbcbf46ef23cd52784fafd
|
||||
F test/corrupt.test 18c7a995b1af76a8c8600b996257f2c7b7bff083
|
||||
F test/corrupt2.test 88342570828f2b8cbbd8369eff3891f5c0bdd5ba
|
||||
F test/crash.test 131259005bb5dbe776eba8de99408a493c69c06c
|
||||
F test/crash.test 504a4eee0ce78f00d16a5a324e42964bd85164f5
|
||||
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
|
||||
F test/date.test 30ca15e608a45d868fd419c901795382efe27020
|
||||
F test/default.test 252298e42a680146b1dd64f563b95bdf088d94fb
|
||||
@ -218,7 +219,7 @@ F test/table.test ec0e6c2186bb8f6824f470caa118524dfd8fe057
|
||||
F test/tableapi.test 6a66d58b37d46dc0f2b3c7d4bd2617d209399bd1
|
||||
F test/tclsqlite.test 2da3e4b3a79b13c1511c9d0cd995e08f8362e782
|
||||
F test/temptable.test 7927261befdbc7b0a7ffebb85ecc70a74fa7b15b
|
||||
F test/tester.tcl bf4e288cd8b968e4514c0bdee27f4f31b21b7271
|
||||
F test/tester.tcl 1dbcac19ed71f68f24b7f5c6c134568d551092ba
|
||||
F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
|
||||
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
|
||||
F test/threadtest2.c 97a830d53c24c42290501fdfba4a6e5bdd34748b
|
||||
@ -321,7 +322,7 @@ F www/tclsqlite.tcl ddcf912ea48695603c8ed7efb29f0812ef8d1b49
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
|
||||
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
|
||||
P f9f5ecbb79f03ba8e7d6a036a562252319e82abc
|
||||
R ccf6548dbbfa01c325708c34e3a65ec7
|
||||
U danielk1977
|
||||
Z 66667bbf44f1416dcd406944ed2382c1
|
||||
P dba2cc0d0e0c648c1a4798bc72913e3b19acba6e
|
||||
R 0354953fb5e466e6ce44febcde77bb5c
|
||||
U drh
|
||||
Z e7c0bd1253129b8abe29fc40e7e0d238
|
||||
|
@ -1 +1 @@
|
||||
dba2cc0d0e0c648c1a4798bc72913e3b19acba6e
|
||||
1f69aec285dd8e26bd739d5e44bb50fe03a9682a
|
49
src/os.h
49
src/os.h
@ -172,28 +172,32 @@ extern unsigned int sqlite3_pending_byte;
|
||||
#define SHARED_FIRST (PENDING_BYTE+2)
|
||||
#define SHARED_SIZE 510
|
||||
|
||||
|
||||
int sqlite3OsDelete(const char*);
|
||||
int sqlite3OsFileExists(const char*);
|
||||
int sqlite3OsOpenReadWrite(const char*, OsFile*, int*);
|
||||
int sqlite3OsOpenExclusive(const char*, OsFile*, int);
|
||||
int sqlite3OsOpenReadOnly(const char*, OsFile*);
|
||||
int sqlite3OsOpenDirectory(const char*, OsFile*);
|
||||
int sqlite3OsSyncDirectory(const char*);
|
||||
int sqlite3OsTempFileName(char*);
|
||||
int sqlite3OsIsDirWritable(char*);
|
||||
int sqlite3OsClose(OsFile*);
|
||||
int sqlite3OsRead(OsFile*, void*, int amt);
|
||||
int sqlite3OsWrite(OsFile*, const void*, int amt);
|
||||
int sqlite3OsSeek(OsFile*, i64 offset);
|
||||
int sqlite3OsSync(OsFile*, int);
|
||||
int sqlite3OsTruncate(OsFile*, i64 size);
|
||||
int sqlite3OsFileSize(OsFile*, i64 *pSize);
|
||||
char *sqlite3OsFullPathname(const char*);
|
||||
int sqlite3OsLock(OsFile*, int);
|
||||
int sqlite3OsUnlock(OsFile*, int);
|
||||
int sqlite3OsCheckReservedLock(OsFile *id);
|
||||
|
||||
/*
|
||||
** A single global instance of the following structure holds pointers to the
|
||||
** various disk I/O routines.
|
||||
*/
|
||||
extern struct sqlite3IoVtbl {
|
||||
int (*xDelete)(const char*);
|
||||
int (*xFileExists)(const char*);
|
||||
int (*xOpenReadWrite)(const char*, OsFile*, int*);
|
||||
int (*xOpenExclusive)(const char*, OsFile*, int);
|
||||
int (*xOpenReadOnly)(const char*, OsFile*);
|
||||
int (*xOpenDirectory)(const char*, OsFile*);
|
||||
int (*xSyncDirectory)(const char*);
|
||||
int (*xTempFileName)(char*);
|
||||
int (*xIsDirWritable)(char*);
|
||||
int (*xClose)(OsFile*);
|
||||
int (*xRead)(OsFile*, void*, int amt);
|
||||
int (*xWrite)(OsFile*, const void*, int amt);
|
||||
int (*xSeek)(OsFile*, i64 offset);
|
||||
int (*xSync)(OsFile*, int);
|
||||
int (*xTruncate)(OsFile*, i64 size);
|
||||
int (*xFileSize)(OsFile*, i64 *pSize);
|
||||
char *(*xFullPathname)(const char*);
|
||||
int (*xLock)(OsFile*, int);
|
||||
int (*xUnlock)(OsFile*, int);
|
||||
int (*xCheckReservedLock)(OsFile *id);
|
||||
} sqlite3Io;
|
||||
|
||||
/* The interface for file I/O is above. Other miscellaneous functions
|
||||
** are below */
|
||||
@ -204,4 +208,5 @@ int sqlite3OsCurrentTime(double*);
|
||||
void sqlite3OsEnterMutex(void);
|
||||
void sqlite3OsLeaveMutex(void);
|
||||
|
||||
|
||||
#endif /* _SQLITE_OS_H_ */
|
||||
|
@ -481,7 +481,7 @@ static int findLockInfo(
|
||||
/*
|
||||
** Delete the named file
|
||||
*/
|
||||
int sqlite3OsDelete(const char *zFilename){
|
||||
static int unixDelete(const char *zFilename){
|
||||
unlink(zFilename);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -489,7 +489,7 @@ int sqlite3OsDelete(const char *zFilename){
|
||||
/*
|
||||
** Return TRUE if the named file exists.
|
||||
*/
|
||||
int sqlite3OsFileExists(const char *zFilename){
|
||||
static int unixFileExists(const char *zFilename){
|
||||
return access(zFilename, 0)==0;
|
||||
}
|
||||
|
||||
@ -506,7 +506,7 @@ int sqlite3OsFileExists(const char *zFilename){
|
||||
** On failure, the function returns SQLITE_CANTOPEN and leaves
|
||||
** *id and *pReadonly unchanged.
|
||||
*/
|
||||
int sqlite3OsOpenReadWrite(
|
||||
static int unixOpenReadWrite(
|
||||
const char *zFilename,
|
||||
OsFile *id,
|
||||
int *pReadonly
|
||||
@ -560,7 +560,7 @@ int sqlite3OsOpenReadWrite(
|
||||
**
|
||||
** On failure, return SQLITE_CANTOPEN.
|
||||
*/
|
||||
int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||
static int unixOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||
int rc;
|
||||
assert( !id->isOpen );
|
||||
if( access(zFilename, 0)==0 ){
|
||||
@ -599,7 +599,7 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||
**
|
||||
** On failure, return SQLITE_CANTOPEN.
|
||||
*/
|
||||
int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
|
||||
static int unixOpenReadOnly(const char *zFilename, OsFile *id){
|
||||
int rc;
|
||||
assert( !id->isOpen );
|
||||
SET_THREADID(id);
|
||||
@ -638,7 +638,7 @@ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
|
||||
** On failure, the function returns SQLITE_CANTOPEN and leaves
|
||||
** *id unchanged.
|
||||
*/
|
||||
int sqlite3OsOpenDirectory(
|
||||
static int unixOpenDirectory(
|
||||
const char *zDirname,
|
||||
OsFile *id
|
||||
){
|
||||
@ -668,7 +668,7 @@ char *sqlite3_temp_directory = 0;
|
||||
** Create a temporary file name in zBuf. zBuf must be big enough to
|
||||
** hold at least SQLITE_TEMPNAME_SIZE characters.
|
||||
*/
|
||||
int sqlite3OsTempFileName(char *zBuf){
|
||||
static int unixTempFileName(char *zBuf){
|
||||
static const char *azDirs[] = {
|
||||
0,
|
||||
"/var/tmp",
|
||||
@ -704,28 +704,28 @@ int sqlite3OsTempFileName(char *zBuf){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
/*
|
||||
** Check that a given pathname is a directory and is writable
|
||||
**
|
||||
*/
|
||||
int sqlite3OsIsDirWritable(char *zBuf){
|
||||
static int unixIsDirWritable(char *zBuf){
|
||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||
struct stat buf;
|
||||
if( zBuf==0 ) return 0;
|
||||
if( zBuf[0]==0 ) return 0;
|
||||
if( stat(zBuf, &buf) ) return 0;
|
||||
if( !S_ISDIR(buf.st_mode) ) return 0;
|
||||
if( access(zBuf, 07) ) return 0;
|
||||
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
|
||||
return 1;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
|
||||
|
||||
/*
|
||||
** Read data from a file into a buffer. Return SQLITE_OK if all
|
||||
** bytes were read successfully and SQLITE_IOERR if anything goes
|
||||
** wrong.
|
||||
*/
|
||||
int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
|
||||
static int unixRead(OsFile *id, void *pBuf, int amt){
|
||||
int got;
|
||||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
@ -746,7 +746,7 @@ int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
|
||||
** Write data from a buffer into a file. Return SQLITE_OK on success
|
||||
** or some other error code on failure.
|
||||
*/
|
||||
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
||||
static int unixWrite(OsFile *id, const void *pBuf, int amt){
|
||||
int wrote = 0;
|
||||
assert( id->isOpen );
|
||||
assert( amt>0 );
|
||||
@ -769,7 +769,7 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
||||
/*
|
||||
** Move the read/write pointer in a file.
|
||||
*/
|
||||
int sqlite3OsSeek(OsFile *id, i64 offset){
|
||||
static int unixSeek(OsFile *id, i64 offset){
|
||||
assert( id->isOpen );
|
||||
SEEK(offset/1024 + 1);
|
||||
#ifdef SQLITE_TEST
|
||||
@ -863,7 +863,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
|
||||
** the directory entry for the journal was never created) and the transaction
|
||||
** will not roll back - possibly leading to database corruption.
|
||||
*/
|
||||
int sqlite3OsSync(OsFile *id, int dataOnly){
|
||||
static int unixSync(OsFile *id, int dataOnly){
|
||||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
TRACE2("SYNC %-3d\n", id->h);
|
||||
@ -891,7 +891,7 @@ int sqlite3OsSync(OsFile *id, int dataOnly){
|
||||
** before making changes to individual journals on a multi-database commit.
|
||||
** The F_FULLFSYNC option is not needed here.
|
||||
*/
|
||||
int sqlite3OsSyncDirectory(const char *zDirname){
|
||||
static int unixSyncDirectory(const char *zDirname){
|
||||
#ifdef SQLITE_DISABLE_DIRSYNC
|
||||
return SQLITE_OK;
|
||||
#else
|
||||
@ -912,7 +912,7 @@ int sqlite3OsSyncDirectory(const char *zDirname){
|
||||
/*
|
||||
** Truncate an open file to a specified size
|
||||
*/
|
||||
int sqlite3OsTruncate(OsFile *id, i64 nByte){
|
||||
static int unixTruncate(OsFile *id, i64 nByte){
|
||||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
return ftruncate(id->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
|
||||
@ -921,7 +921,7 @@ int sqlite3OsTruncate(OsFile *id, i64 nByte){
|
||||
/*
|
||||
** Determine the current size of a file in bytes
|
||||
*/
|
||||
int sqlite3OsFileSize(OsFile *id, i64 *pSize){
|
||||
static int unixFileSize(OsFile *id, i64 *pSize){
|
||||
struct stat buf;
|
||||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
@ -938,7 +938,7 @@ int sqlite3OsFileSize(OsFile *id, i64 *pSize){
|
||||
** non-zero. If the file is unlocked or holds only SHARED locks, then
|
||||
** return zero.
|
||||
*/
|
||||
int sqlite3OsCheckReservedLock(OsFile *id){
|
||||
static int unixCheckReservedLock(OsFile *id){
|
||||
int r = 0;
|
||||
|
||||
assert( id->isOpen );
|
||||
@ -1012,7 +1012,7 @@ static const char * locktypeName(int locktype){
|
||||
** This routine will only increase a lock. Use the sqlite3OsUnlock()
|
||||
** routine to lower a locking level.
|
||||
*/
|
||||
int sqlite3OsLock(OsFile *id, int locktype){
|
||||
static int unixLock(OsFile *id, int locktype){
|
||||
/* The following describes the implementation of the various locks and
|
||||
** lock transitions in terms of the POSIX advisory shared and exclusive
|
||||
** lock primitives (called read-locks and write-locks below, to avoid
|
||||
@ -1208,7 +1208,7 @@ end_lock:
|
||||
** is NO_LOCK. If the second argument is SHARED_LOCK, this routine
|
||||
** might return SQLITE_IOERR instead of SQLITE_OK.
|
||||
*/
|
||||
int sqlite3OsUnlock(OsFile *id, int locktype){
|
||||
static int unixUnlock(OsFile *id, int locktype){
|
||||
struct lockInfo *pLock;
|
||||
struct flock lock;
|
||||
int rc = SQLITE_OK;
|
||||
@ -1291,10 +1291,10 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
|
||||
/*
|
||||
** Close a file.
|
||||
*/
|
||||
int sqlite3OsClose(OsFile *id){
|
||||
static int unixClose(OsFile *id){
|
||||
if( !id->isOpen ) return SQLITE_OK;
|
||||
if( CHECK_THREADID(id) ) return SQLITE_MISUSE;
|
||||
sqlite3OsUnlock(id, NO_LOCK);
|
||||
sqlite3Io.xUnlock(id, NO_LOCK);
|
||||
if( id->dirfd>=0 ) close(id->dirfd);
|
||||
id->dirfd = -1;
|
||||
sqlite3OsEnterMutex();
|
||||
@ -1333,7 +1333,7 @@ int sqlite3OsClose(OsFile *id){
|
||||
** The calling function is responsible for freeing this space once it
|
||||
** is no longer needed.
|
||||
*/
|
||||
char *sqlite3OsFullPathname(const char *zRelative){
|
||||
static char *unixFullPathname(const char *zRelative){
|
||||
char *zFull = 0;
|
||||
if( zRelative[0]=='/' ){
|
||||
sqlite3SetString(&zFull, zRelative, (char*)0);
|
||||
@ -1351,6 +1351,33 @@ char *sqlite3OsFullPathname(const char *zRelative){
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This is the structure that defines all of the I/O routines.
|
||||
*/
|
||||
struct sqlite3IoVtbl sqlite3Io = {
|
||||
unixDelete,
|
||||
unixFileExists,
|
||||
unixOpenReadWrite,
|
||||
unixOpenExclusive,
|
||||
unixOpenReadOnly,
|
||||
unixOpenDirectory,
|
||||
unixSyncDirectory,
|
||||
unixTempFileName,
|
||||
unixIsDirWritable,
|
||||
unixClose,
|
||||
unixRead,
|
||||
unixWrite,
|
||||
unixSeek,
|
||||
unixSync,
|
||||
unixTruncate,
|
||||
unixFileSize,
|
||||
unixFullPathname,
|
||||
unixLock,
|
||||
unixUnlock,
|
||||
unixCheckReservedLock,
|
||||
};
|
||||
|
||||
|
||||
#endif /* SQLITE_OMIT_DISKIO */
|
||||
/***************************************************************************
|
||||
** Everything above deals with file I/O. Everything that follows deals
|
||||
|
70
src/os_win.c
70
src/os_win.c
@ -126,7 +126,7 @@ static char *unicodeToUtf8(const WCHAR *zWideFilename){
|
||||
/*
|
||||
** Delete the named file
|
||||
*/
|
||||
int sqlite3OsDelete(const char *zFilename){
|
||||
static int winDelete(const char *zFilename){
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
if( zWide ){
|
||||
DeleteFileW(zWide);
|
||||
@ -141,7 +141,7 @@ int sqlite3OsDelete(const char *zFilename){
|
||||
/*
|
||||
** Return TRUE if the named file exists.
|
||||
*/
|
||||
int sqlite3OsFileExists(const char *zFilename){
|
||||
static int winFileExists(const char *zFilename){
|
||||
int exists = 0;
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
if( zWide ){
|
||||
@ -166,7 +166,7 @@ int sqlite3OsFileExists(const char *zFilename){
|
||||
** On failure, the function returns SQLITE_CANTOPEN and leaves
|
||||
** *id and *pReadonly unchanged.
|
||||
*/
|
||||
int sqlite3OsOpenReadWrite(
|
||||
static int winOpenReadWrite(
|
||||
const char *zFilename,
|
||||
OsFile *id,
|
||||
int *pReadonly
|
||||
@ -251,7 +251,7 @@ int sqlite3OsOpenReadWrite(
|
||||
**
|
||||
** On failure, return SQLITE_CANTOPEN.
|
||||
*/
|
||||
int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||
static int winOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||
HANDLE h;
|
||||
int fileflags;
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
@ -301,7 +301,7 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||
**
|
||||
** On failure, return SQLITE_CANTOPEN.
|
||||
*/
|
||||
int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
|
||||
static int winOpenReadOnly(const char *zFilename, OsFile *id){
|
||||
HANDLE h;
|
||||
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||
assert( !id->isOpen );
|
||||
@ -353,7 +353,7 @@ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
|
||||
** On failure, the function returns SQLITE_CANTOPEN and leaves
|
||||
** *id unchanged.
|
||||
*/
|
||||
int sqlite3OsOpenDirectory(
|
||||
static int winOpenDirectory(
|
||||
const char *zDirname,
|
||||
OsFile *id
|
||||
){
|
||||
@ -371,7 +371,7 @@ char *sqlite3_temp_directory = 0;
|
||||
** Create a temporary file name in zBuf. zBuf must be big enough to
|
||||
** hold at least SQLITE_TEMPNAME_SIZE characters.
|
||||
*/
|
||||
int sqlite3OsTempFileName(char *zBuf){
|
||||
static int winTempFileName(char *zBuf){
|
||||
static char zChars[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
@ -404,7 +404,7 @@ int sqlite3OsTempFileName(char *zBuf){
|
||||
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
|
||||
}
|
||||
zBuf[j] = 0;
|
||||
if( !sqlite3OsFileExists(zBuf) ) break;
|
||||
if( !sqlite3Io.xFileExists(zBuf) ) break;
|
||||
}
|
||||
TRACE2("TEMP FILENAME: %s\n", zBuf);
|
||||
return SQLITE_OK;
|
||||
@ -413,7 +413,7 @@ int sqlite3OsTempFileName(char *zBuf){
|
||||
/*
|
||||
** Close a file.
|
||||
*/
|
||||
int sqlite3OsClose(OsFile *id){
|
||||
static int winClose(OsFile *id){
|
||||
if( id->isOpen ){
|
||||
TRACE2("CLOSE %d\n", id->h);
|
||||
CloseHandle(id->h);
|
||||
@ -428,7 +428,7 @@ int sqlite3OsClose(OsFile *id){
|
||||
** bytes were read successfully and SQLITE_IOERR if anything goes
|
||||
** wrong.
|
||||
*/
|
||||
int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
|
||||
static int winRead(OsFile *id, void *pBuf, int amt){
|
||||
DWORD got;
|
||||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
@ -447,7 +447,7 @@ int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
|
||||
** Write data from a buffer into a file. Return SQLITE_OK on success
|
||||
** or some other error code on failure.
|
||||
*/
|
||||
int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
||||
static int winWrite(OsFile *id, const void *pBuf, int amt){
|
||||
int rc = 0;
|
||||
DWORD wrote;
|
||||
assert( id->isOpen );
|
||||
@ -475,7 +475,7 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
||||
/*
|
||||
** Move the read/write pointer in a file.
|
||||
*/
|
||||
int sqlite3OsSeek(OsFile *id, i64 offset){
|
||||
static int winSeek(OsFile *id, i64 offset){
|
||||
LONG upperBits = offset>>32;
|
||||
LONG lowerBits = offset & 0xffffffff;
|
||||
DWORD rc;
|
||||
@ -495,7 +495,7 @@ int sqlite3OsSeek(OsFile *id, i64 offset){
|
||||
/*
|
||||
** Make sure all writes to a particular file are committed to disk.
|
||||
*/
|
||||
int sqlite3OsSync(OsFile *id, int dataOnly){
|
||||
static int winSync(OsFile *id, int dataOnly){
|
||||
assert( id->isOpen );
|
||||
TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
|
||||
if( FlushFileBuffers(id->h) ){
|
||||
@ -509,7 +509,7 @@ int sqlite3OsSync(OsFile *id, int dataOnly){
|
||||
** Sync the directory zDirname. This is a no-op on operating systems other
|
||||
** than UNIX.
|
||||
*/
|
||||
int sqlite3OsSyncDirectory(const char *zDirname){
|
||||
static int winSyncDirectory(const char *zDirname){
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -517,7 +517,7 @@ int sqlite3OsSyncDirectory(const char *zDirname){
|
||||
/*
|
||||
** Truncate an open file to a specified size
|
||||
*/
|
||||
int sqlite3OsTruncate(OsFile *id, i64 nByte){
|
||||
static int winTruncate(OsFile *id, i64 nByte){
|
||||
LONG upperBits = nByte>>32;
|
||||
assert( id->isOpen );
|
||||
TRACE3("TRUNCATE %d %lld\n", id->h, nByte);
|
||||
@ -530,7 +530,7 @@ int sqlite3OsTruncate(OsFile *id, i64 nByte){
|
||||
/*
|
||||
** Determine the current size of a file in bytes
|
||||
*/
|
||||
int sqlite3OsFileSize(OsFile *id, i64 *pSize){
|
||||
static int winFileSize(OsFile *id, i64 *pSize){
|
||||
DWORD upperBits, lowerBits;
|
||||
assert( id->isOpen );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
@ -579,7 +579,7 @@ static int unlockReadLock(OsFile *id){
|
||||
** Check that a given pathname is a directory and is writable
|
||||
**
|
||||
*/
|
||||
int sqlite3OsIsDirWritable(char *zDirname){
|
||||
static int winIsDirWritable(char *zDirname){
|
||||
int fileAttr;
|
||||
WCHAR *zWide;
|
||||
if( zDirname==0 ) return 0;
|
||||
@ -620,12 +620,12 @@ int sqlite3OsIsDirWritable(char *zDirname){
|
||||
** RESERVED -> (PENDING) -> EXCLUSIVE
|
||||
** PENDING -> EXCLUSIVE
|
||||
**
|
||||
** This routine will only increase a lock. The sqlite3OsUnlock() routine
|
||||
** This routine will only increase a lock. The winUnlock() routine
|
||||
** erases all locks at once and returns us immediately to locking level 0.
|
||||
** It is not possible to lower the locking level one step at a time. You
|
||||
** must go straight to locking level 0.
|
||||
*/
|
||||
int sqlite3OsLock(OsFile *id, int locktype){
|
||||
static int winLock(OsFile *id, int locktype){
|
||||
int rc = SQLITE_OK; /* Return code from subroutines */
|
||||
int res = 1; /* Result of a windows lock call */
|
||||
int newLocktype; /* Set id->locktype to this value before exiting */
|
||||
@ -735,7 +735,7 @@ int sqlite3OsLock(OsFile *id, int locktype){
|
||||
** file by this or any other process. If such a lock is held, return
|
||||
** non-zero, otherwise zero.
|
||||
*/
|
||||
int sqlite3OsCheckReservedLock(OsFile *id){
|
||||
static int winCheckReservedLock(OsFile *id){
|
||||
int rc;
|
||||
assert( id->isOpen );
|
||||
if( id->locktype>=RESERVED_LOCK ){
|
||||
@ -763,7 +763,7 @@ int sqlite3OsCheckReservedLock(OsFile *id){
|
||||
** is NO_LOCK. If the second argument is SHARED_LOCK then this routine
|
||||
** might return SQLITE_IOERR;
|
||||
*/
|
||||
int sqlite3OsUnlock(OsFile *id, int locktype){
|
||||
static int winUnlock(OsFile *id, int locktype){
|
||||
int type;
|
||||
int rc = SQLITE_OK;
|
||||
assert( id->isOpen );
|
||||
@ -798,7 +798,7 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
|
||||
** The calling function is responsible for freeing this space once it
|
||||
** is no longer needed.
|
||||
*/
|
||||
char *sqlite3OsFullPathname(const char *zRelative){
|
||||
static char *winFullPathname(const char *zRelative){
|
||||
char *zNotUsed;
|
||||
char *zFull;
|
||||
WCHAR *zWide;
|
||||
@ -829,6 +829,32 @@ char *sqlite3OsFullPathname(const char *zRelative){
|
||||
return zFull;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is the structure that defines all of the I/O routines.
|
||||
*/
|
||||
struct sqlite3IoVtbl sqlite3Io = {
|
||||
winDelete,
|
||||
winFileExists,
|
||||
winOpenReadWrite,
|
||||
winOpenExclusive,
|
||||
winOpenReadOnly,
|
||||
winOpenDirectory,
|
||||
winSyncDirectory,
|
||||
winTempFileName,
|
||||
winIsDirWritable,
|
||||
winClose,
|
||||
winRead,
|
||||
winWrite,
|
||||
winSeek,
|
||||
winSync,
|
||||
winTruncate,
|
||||
winFileSize,
|
||||
winFullPathname,
|
||||
winLock,
|
||||
winUnlock,
|
||||
winCheckReservedLock,
|
||||
};
|
||||
|
||||
#endif /* SQLITE_OMIT_DISKIO */
|
||||
/***************************************************************************
|
||||
** Everything above deals with file I/O. Everything that follows deals
|
||||
|
189
src/pager.c
189
src/pager.c
@ -18,7 +18,7 @@
|
||||
** file simultaneously, or one process from reading the database while
|
||||
** another is writing.
|
||||
**
|
||||
** @(#) $Id: pager.c,v 1.217 2005/11/05 15:11:23 drh Exp $
|
||||
** @(#) $Id: pager.c,v 1.218 2005/11/26 00:25:03 drh Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
#include "sqliteInt.h"
|
||||
@ -413,7 +413,7 @@ static const unsigned char aJournalMagic[] = {
|
||||
static int read32bits(OsFile *fd, u32 *pRes){
|
||||
u32 res;
|
||||
int rc;
|
||||
rc = sqlite3OsRead(fd, &res, sizeof(res));
|
||||
rc = sqlite3Io.xRead(fd, &res, sizeof(res));
|
||||
if( rc==SQLITE_OK ){
|
||||
unsigned char ac[4];
|
||||
memcpy(ac, &res, 4);
|
||||
@ -433,7 +433,7 @@ static int write32bits(OsFile *fd, u32 val){
|
||||
ac[1] = (val>>16) & 0xff;
|
||||
ac[2] = (val>>8) & 0xff;
|
||||
ac[3] = val & 0xff;
|
||||
return sqlite3OsWrite(fd, ac, 4);
|
||||
return sqlite3Io.xWrite(fd, ac, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -524,10 +524,10 @@ static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
|
||||
|
||||
*pzMaster = 0;
|
||||
|
||||
rc = sqlite3OsFileSize(pJrnl, &szJ);
|
||||
rc = sqlite3Io.xFileSize(pJrnl, &szJ);
|
||||
if( rc!=SQLITE_OK || szJ<16 ) return rc;
|
||||
|
||||
rc = sqlite3OsSeek(pJrnl, szJ-16);
|
||||
rc = sqlite3Io.xSeek(pJrnl, szJ-16);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = read32bits(pJrnl, &len);
|
||||
@ -536,17 +536,17 @@ static int readMasterJournal(OsFile *pJrnl, char **pzMaster){
|
||||
rc = read32bits(pJrnl, &cksum);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = sqlite3OsRead(pJrnl, aMagic, 8);
|
||||
rc = sqlite3Io.xRead(pJrnl, aMagic, 8);
|
||||
if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, 8) ) return rc;
|
||||
|
||||
rc = sqlite3OsSeek(pJrnl, szJ-16-len);
|
||||
rc = sqlite3Io.xSeek(pJrnl, szJ-16-len);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
*pzMaster = (char *)sqliteMalloc(len+1);
|
||||
if( !*pzMaster ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
rc = sqlite3OsRead(pJrnl, *pzMaster, len);
|
||||
rc = sqlite3Io.xRead(pJrnl, *pzMaster, len);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteFree(*pzMaster);
|
||||
*pzMaster = 0;
|
||||
@ -597,7 +597,7 @@ static int seekJournalHdr(Pager *pPager){
|
||||
assert( offset>=c );
|
||||
assert( (offset-c)<JOURNAL_HDR_SZ(pPager) );
|
||||
pPager->journalOff = offset;
|
||||
return sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
|
||||
return sqlite3Io.xSeek(&pPager->jfd, pPager->journalOff);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -633,7 +633,7 @@ static int writeJournalHdr(Pager *pPager){
|
||||
** Actually maybe the whole journal header should be delayed until that
|
||||
** point. Think about this.
|
||||
*/
|
||||
rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
|
||||
rc = sqlite3Io.xWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
/* The nRec Field. 0xFFFFFFFF for no-sync journals. */
|
||||
@ -657,9 +657,9 @@ static int writeJournalHdr(Pager *pPager){
|
||||
** file descriptor to the end of the journal header sector.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1);
|
||||
rc = sqlite3Io.xSeek(&pPager->jfd, pPager->journalOff-1);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsWrite(&pPager->jfd, "\000", 1);
|
||||
rc = sqlite3Io.xWrite(&pPager->jfd, "\000", 1);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@ -697,7 +697,7 @@ static int readJournalHdr(
|
||||
return SQLITE_DONE;
|
||||
}
|
||||
|
||||
rc = sqlite3OsRead(&pPager->jfd, aMagic, sizeof(aMagic));
|
||||
rc = sqlite3Io.xRead(&pPager->jfd, aMagic, sizeof(aMagic));
|
||||
if( rc ) return rc;
|
||||
|
||||
if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){
|
||||
@ -723,7 +723,7 @@ static int readJournalHdr(
|
||||
if( rc ) return rc;
|
||||
|
||||
pPager->journalOff += JOURNAL_HDR_SZ(pPager);
|
||||
rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
|
||||
rc = sqlite3Io.xSeek(&pPager->jfd, pPager->journalOff);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -771,7 +771,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
||||
rc = write32bits(&pPager->jfd, PAGER_MJ_PGNO(pPager));
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = sqlite3OsWrite(&pPager->jfd, zMaster, len);
|
||||
rc = sqlite3Io.xWrite(&pPager->jfd, zMaster, len);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = write32bits(&pPager->jfd, len);
|
||||
@ -780,7 +780,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
||||
rc = write32bits(&pPager->jfd, cksum);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
|
||||
rc = sqlite3Io.xWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
|
||||
pPager->needSync = !pPager->noSync;
|
||||
return rc;
|
||||
}
|
||||
@ -858,7 +858,7 @@ static void pager_reset(Pager *pPager){
|
||||
if( pPager->state>=PAGER_RESERVED ){
|
||||
sqlite3pager_rollback(pPager);
|
||||
}
|
||||
sqlite3OsUnlock(&pPager->fd, NO_LOCK);
|
||||
sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
|
||||
pPager->state = PAGER_UNLOCK;
|
||||
pPager->dbSize = -1;
|
||||
pPager->nRef = 0;
|
||||
@ -907,13 +907,13 @@ static int pager_unwritelock(Pager *pPager){
|
||||
}
|
||||
sqlite3pager_stmt_commit(pPager);
|
||||
if( pPager->stmtOpen ){
|
||||
sqlite3OsClose(&pPager->stfd);
|
||||
sqlite3Io.xClose(&pPager->stfd);
|
||||
pPager->stmtOpen = 0;
|
||||
}
|
||||
if( pPager->journalOpen ){
|
||||
sqlite3OsClose(&pPager->jfd);
|
||||
sqlite3Io.xClose(&pPager->jfd);
|
||||
pPager->journalOpen = 0;
|
||||
sqlite3OsDelete(pPager->zJournal);
|
||||
sqlite3Io.xDelete(pPager->zJournal);
|
||||
sqliteFree( pPager->aInJournal );
|
||||
pPager->aInJournal = 0;
|
||||
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
|
||||
@ -930,7 +930,7 @@ static int pager_unwritelock(Pager *pPager){
|
||||
assert( pPager->aInJournal==0 );
|
||||
assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
|
||||
}
|
||||
rc = sqlite3OsUnlock(&pPager->fd, SHARED_LOCK);
|
||||
rc = sqlite3Io.xUnlock(&pPager->fd, SHARED_LOCK);
|
||||
pPager->state = PAGER_SHARED;
|
||||
pPager->origDbSize = 0;
|
||||
pPager->setMaster = 0;
|
||||
@ -990,7 +990,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
|
||||
|
||||
rc = read32bits(jfd, &pgno);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
rc = sqlite3OsRead(jfd, &aData, pPager->pageSize);
|
||||
rc = sqlite3Io.xRead(jfd, &aData, pPager->pageSize);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
pPager->journalOff += pPager->pageSize + 4;
|
||||
|
||||
@ -1040,9 +1040,9 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
|
||||
assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
|
||||
TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
|
||||
if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
|
||||
rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
||||
rc = sqlite3Io.xSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
|
||||
rc = sqlite3Io.xWrite(&pPager->fd, aData, pPager->pageSize);
|
||||
}
|
||||
if( pPg ) pPg->dirty = 0;
|
||||
}
|
||||
@ -1090,10 +1090,10 @@ static int pager_delmaster(const char *zMaster){
|
||||
** is running this routine also. Not that it makes too much difference.
|
||||
*/
|
||||
memset(&master, 0, sizeof(master));
|
||||
rc = sqlite3OsOpenReadOnly(zMaster, &master);
|
||||
rc = sqlite3Io.xOpenReadOnly(zMaster, &master);
|
||||
if( rc!=SQLITE_OK ) goto delmaster_out;
|
||||
master_open = 1;
|
||||
rc = sqlite3OsFileSize(&master, &nMasterJournal);
|
||||
rc = sqlite3Io.xFileSize(&master, &nMasterJournal);
|
||||
if( rc!=SQLITE_OK ) goto delmaster_out;
|
||||
|
||||
if( nMasterJournal>0 ){
|
||||
@ -1108,12 +1108,12 @@ static int pager_delmaster(const char *zMaster){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto delmaster_out;
|
||||
}
|
||||
rc = sqlite3OsRead(&master, zMasterJournal, nMasterJournal);
|
||||
rc = sqlite3Io.xRead(&master, zMasterJournal, nMasterJournal);
|
||||
if( rc!=SQLITE_OK ) goto delmaster_out;
|
||||
|
||||
zJournal = zMasterJournal;
|
||||
while( (zJournal-zMasterJournal)<nMasterJournal ){
|
||||
if( sqlite3OsFileExists(zJournal) ){
|
||||
if( sqlite3Io.xFileExists(zJournal) ){
|
||||
/* One of the journals pointed to by the master journal exists.
|
||||
** Open it and check if it points at the master journal. If
|
||||
** so, return without deleting the master journal file.
|
||||
@ -1122,13 +1122,13 @@ static int pager_delmaster(const char *zMaster){
|
||||
int c;
|
||||
|
||||
memset(&journal, 0, sizeof(journal));
|
||||
rc = sqlite3OsOpenReadOnly(zJournal, &journal);
|
||||
rc = sqlite3Io.xOpenReadOnly(zJournal, &journal);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto delmaster_out;
|
||||
}
|
||||
|
||||
rc = readMasterJournal(&journal, &zMasterPtr);
|
||||
sqlite3OsClose(&journal);
|
||||
sqlite3Io.xClose(&journal);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto delmaster_out;
|
||||
}
|
||||
@ -1144,14 +1144,14 @@ static int pager_delmaster(const char *zMaster){
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3OsDelete(zMaster);
|
||||
sqlite3Io.xDelete(zMaster);
|
||||
|
||||
delmaster_out:
|
||||
if( zMasterJournal ){
|
||||
sqliteFree(zMasterJournal);
|
||||
}
|
||||
if( master_open ){
|
||||
sqlite3OsClose(&master);
|
||||
sqlite3Io.xClose(&master);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -1172,9 +1172,9 @@ static int pager_reload_cache(Pager *pPager){
|
||||
char zBuf[SQLITE_MAX_PAGE_SIZE];
|
||||
if( !pPg->dirty ) continue;
|
||||
if( (int)pPg->pgno <= pPager->origDbSize ){
|
||||
rc = sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
|
||||
rc = sqlite3Io.xSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
|
||||
rc = sqlite3Io.xRead(&pPager->fd, zBuf, pPager->pageSize);
|
||||
}
|
||||
TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||
if( rc ) break;
|
||||
@ -1205,7 +1205,7 @@ static int pager_reload_cache(Pager *pPager){
|
||||
*/
|
||||
static int pager_truncate(Pager *pPager, int nPage){
|
||||
assert( pPager->state>=PAGER_EXCLUSIVE );
|
||||
return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(i64)nPage);
|
||||
return sqlite3Io.xTruncate(&pPager->fd, pPager->pageSize*(i64)nPage);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1273,7 +1273,7 @@ static int pager_playback(Pager *pPager){
|
||||
** the journal is empty.
|
||||
*/
|
||||
assert( pPager->journalOpen );
|
||||
rc = sqlite3OsFileSize(&pPager->jfd, &szJ);
|
||||
rc = sqlite3Io.xFileSize(&pPager->jfd, &szJ);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto end_playback;
|
||||
}
|
||||
@ -1285,13 +1285,13 @@ static int pager_playback(Pager *pPager){
|
||||
*/
|
||||
rc = readMasterJournal(&pPager->jfd, &zMaster);
|
||||
assert( rc!=SQLITE_DONE );
|
||||
if( rc!=SQLITE_OK || (zMaster && !sqlite3OsFileExists(zMaster)) ){
|
||||
if( rc!=SQLITE_OK || (zMaster && !sqlite3Io.xFileExists(zMaster)) ){
|
||||
sqliteFree(zMaster);
|
||||
zMaster = 0;
|
||||
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
|
||||
goto end_playback;
|
||||
}
|
||||
sqlite3OsSeek(&pPager->jfd, 0);
|
||||
sqlite3Io.xSeek(&pPager->jfd, 0);
|
||||
pPager->journalOff = 0;
|
||||
|
||||
/* This loop terminates either when the readJournalHdr() call returns
|
||||
@ -1334,7 +1334,7 @@ static int pager_playback(Pager *pPager){
|
||||
pPager->dbSize = mxPg;
|
||||
}
|
||||
|
||||
/* rc = sqlite3OsSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */
|
||||
/* rc = sqlite3Io.xSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */
|
||||
if( rc!=SQLITE_OK ) goto end_playback;
|
||||
|
||||
/* Copy original pages out of the journal and back into the database file.
|
||||
@ -1407,7 +1407,7 @@ static int pager_stmt_playback(Pager *pPager){
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
i64 os_szJ;
|
||||
rc = sqlite3OsFileSize(&pPager->jfd, &os_szJ);
|
||||
rc = sqlite3Io.xFileSize(&pPager->jfd, &os_szJ);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
assert( szJ==os_szJ );
|
||||
}
|
||||
@ -1433,7 +1433,7 @@ static int pager_stmt_playback(Pager *pPager){
|
||||
/* Figure out how many records are in the statement journal.
|
||||
*/
|
||||
assert( pPager->stmtInUse && pPager->journalOpen );
|
||||
sqlite3OsSeek(&pPager->stfd, 0);
|
||||
sqlite3Io.xSeek(&pPager->stfd, 0);
|
||||
nRec = pPager->stmtNRec;
|
||||
|
||||
/* Copy original pages out of the statement journal and back into the
|
||||
@ -1455,7 +1455,7 @@ static int pager_stmt_playback(Pager *pPager){
|
||||
** If it is not zero, then Pager.stmtHdrOff is the offset to the start
|
||||
** of the first journal header written during this statement transaction.
|
||||
*/
|
||||
rc = sqlite3OsSeek(&pPager->jfd, pPager->stmtJSize);
|
||||
rc = sqlite3Io.xSeek(&pPager->jfd, pPager->stmtJSize);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto end_stmt_playback;
|
||||
}
|
||||
@ -1515,7 +1515,7 @@ void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
|
||||
** or power failures by changing the number of syncs()s when writing
|
||||
** the rollback journal. There are three levels:
|
||||
**
|
||||
** OFF sqlite3OsSync() is never called. This is the default
|
||||
** OFF sqlite3Io.xSync() is never called. This is the default
|
||||
** for temporary and transient files.
|
||||
**
|
||||
** NORMAL The journal is synced once before writes begin on the
|
||||
@ -1566,8 +1566,8 @@ static int sqlite3pager_opentemp(char *zFile, OsFile *fd){
|
||||
sqlite3_opentemp_count++; /* Used for testing and analysis only */
|
||||
do{
|
||||
cnt--;
|
||||
sqlite3OsTempFileName(zFile);
|
||||
rc = sqlite3OsOpenExclusive(zFile, fd, 1);
|
||||
sqlite3Io.xTempFileName(zFile);
|
||||
rc = sqlite3Io.xOpenExclusive(zFile, fd, 1);
|
||||
}while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM );
|
||||
return rc;
|
||||
}
|
||||
@ -1619,32 +1619,32 @@ int sqlite3pager_open(
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
zFullPathname = sqlite3OsFullPathname(zFilename);
|
||||
zFullPathname = sqlite3Io.xFullPathname(zFilename);
|
||||
if( zFullPathname ){
|
||||
rc = sqlite3OsOpenReadWrite(zFullPathname, &fd, &readOnly);
|
||||
rc = sqlite3Io.xOpenReadWrite(zFullPathname, &fd, &readOnly);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
rc = sqlite3pager_opentemp(zTemp, &fd);
|
||||
zFilename = zTemp;
|
||||
zFullPathname = sqlite3OsFullPathname(zFilename);
|
||||
zFullPathname = sqlite3Io.xFullPathname(zFilename);
|
||||
if( rc==SQLITE_OK ){
|
||||
tempFile = 1;
|
||||
}
|
||||
}
|
||||
if( !zFullPathname ){
|
||||
sqlite3OsClose(&fd);
|
||||
sqlite3Io.xClose(&fd);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsClose(&fd);
|
||||
sqlite3Io.xClose(&fd);
|
||||
sqliteFree(zFullPathname);
|
||||
return rc;
|
||||
}
|
||||
nameLen = strlen(zFullPathname);
|
||||
pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
|
||||
if( pPager==0 ){
|
||||
sqlite3OsClose(&fd);
|
||||
sqlite3Io.xClose(&fd);
|
||||
sqliteFree(zFullPathname);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -1660,9 +1660,6 @@ int sqlite3pager_open(
|
||||
sqliteFree(zFullPathname);
|
||||
strcpy(&pPager->zJournal[nameLen], "-journal");
|
||||
pPager->fd = fd;
|
||||
#if OS_UNIX
|
||||
pPager->fd.pPager = pPager;
|
||||
#endif
|
||||
pPager->journalOpen = 0;
|
||||
pPager->useJournal = useJournal && !memDb;
|
||||
pPager->noReadlock = noReadlock && readOnly;
|
||||
@ -1773,8 +1770,8 @@ void enable_simulated_io_errors(void){
|
||||
void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
|
||||
memset(pDest, 0, N);
|
||||
if( MEMDB==0 ){
|
||||
sqlite3OsSeek(&pPager->fd, 0);
|
||||
sqlite3OsRead(&pPager->fd, pDest, N);
|
||||
sqlite3Io.xSeek(&pPager->fd, 0);
|
||||
sqlite3Io.xRead(&pPager->fd, pDest, N);
|
||||
clear_simulated_io_error();
|
||||
}
|
||||
}
|
||||
@ -1794,7 +1791,7 @@ int sqlite3pager_pagecount(Pager *pPager){
|
||||
if( pPager->dbSize>=0 ){
|
||||
n = pPager->dbSize;
|
||||
} else {
|
||||
if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
|
||||
if( sqlite3Io.xFileSize(&pPager->fd, &n)!=SQLITE_OK ){
|
||||
pPager->errMask |= PAGER_ERR_DISK;
|
||||
return 0;
|
||||
}
|
||||
@ -1926,7 +1923,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
do {
|
||||
rc = sqlite3OsLock(&pPager->fd, locktype);
|
||||
rc = sqlite3Io.xLock(&pPager->fd, locktype);
|
||||
}while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) );
|
||||
if( rc==SQLITE_OK ){
|
||||
pPager->state = locktype;
|
||||
@ -1994,14 +1991,14 @@ int sqlite3pager_close(Pager *pPager){
|
||||
sqlite3pager_rollback(pPager);
|
||||
enable_simulated_io_errors();
|
||||
if( !MEMDB ){
|
||||
sqlite3OsUnlock(&pPager->fd, NO_LOCK);
|
||||
sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
|
||||
}
|
||||
assert( pPager->errMask || pPager->journalOpen==0 );
|
||||
break;
|
||||
}
|
||||
case PAGER_SHARED: {
|
||||
if( !MEMDB ){
|
||||
sqlite3OsUnlock(&pPager->fd, NO_LOCK);
|
||||
sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2025,16 +2022,16 @@ int sqlite3pager_close(Pager *pPager){
|
||||
TRACE2("CLOSE %d\n", PAGERID(pPager));
|
||||
assert( pPager->errMask || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
|
||||
if( pPager->journalOpen ){
|
||||
sqlite3OsClose(&pPager->jfd);
|
||||
sqlite3Io.xClose(&pPager->jfd);
|
||||
}
|
||||
sqliteFree(pPager->aInJournal);
|
||||
if( pPager->stmtOpen ){
|
||||
sqlite3OsClose(&pPager->stfd);
|
||||
sqlite3Io.xClose(&pPager->stfd);
|
||||
}
|
||||
sqlite3OsClose(&pPager->fd);
|
||||
sqlite3Io.xClose(&pPager->fd);
|
||||
/* Temp files are automatically deleted by the OS
|
||||
** if( pPager->tempFile ){
|
||||
** sqlite3OsDelete(pPager->zFilename);
|
||||
** sqlite3Io.xDelete(pPager->zFilename);
|
||||
** }
|
||||
*/
|
||||
|
||||
@ -2143,7 +2140,7 @@ static int syncJournal(Pager *pPager){
|
||||
** with the nRec computed from the size of the journal file.
|
||||
*/
|
||||
i64 jSz;
|
||||
rc = sqlite3OsFileSize(&pPager->jfd, &jSz);
|
||||
rc = sqlite3Io.xFileSize(&pPager->jfd, &jSz);
|
||||
if( rc!=0 ) return rc;
|
||||
assert( pPager->journalOff==jSz );
|
||||
}
|
||||
@ -2156,20 +2153,20 @@ static int syncJournal(Pager *pPager){
|
||||
*/
|
||||
if( pPager->fullSync ){
|
||||
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
|
||||
rc = sqlite3OsSync(&pPager->jfd, 0);
|
||||
rc = sqlite3Io.xSync(&pPager->jfd, 0);
|
||||
if( rc!=0 ) return rc;
|
||||
}
|
||||
rc = sqlite3OsSeek(&pPager->jfd,
|
||||
rc = sqlite3Io.xSeek(&pPager->jfd,
|
||||
pPager->journalHdr + sizeof(aJournalMagic));
|
||||
if( rc ) return rc;
|
||||
rc = write32bits(&pPager->jfd, pPager->nRec);
|
||||
if( rc ) return rc;
|
||||
|
||||
rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
|
||||
rc = sqlite3Io.xSeek(&pPager->jfd, pPager->journalOff);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
|
||||
rc = sqlite3OsSync(&pPager->jfd, pPager->fullSync);
|
||||
rc = sqlite3Io.xSync(&pPager->jfd, pPager->fullSync);
|
||||
if( rc!=0 ) return rc;
|
||||
pPager->journalStarted = 1;
|
||||
}
|
||||
@ -2213,7 +2210,7 @@ static int pager_write_pagelist(PgHdr *pList){
|
||||
|
||||
/* At this point there may be either a RESERVED or EXCLUSIVE lock on the
|
||||
** database file. If there is already an EXCLUSIVE lock, the following
|
||||
** calls to sqlite3OsLock() are no-ops.
|
||||
** calls to sqlite3Io.xLock() are no-ops.
|
||||
**
|
||||
** Moving the lock from RESERVED to EXCLUSIVE actually involves going
|
||||
** through an intermediate state PENDING. A PENDING lock prevents new
|
||||
@ -2234,7 +2231,7 @@ static int pager_write_pagelist(PgHdr *pList){
|
||||
|
||||
while( pList ){
|
||||
assert( pList->dirty );
|
||||
rc = sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
|
||||
rc = sqlite3Io.xSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
|
||||
if( rc ) return rc;
|
||||
/* If there are dirty pages in the page cache with page numbers greater
|
||||
** than Pager.dbSize, this means sqlite3pager_truncate() was called to
|
||||
@ -2244,7 +2241,8 @@ static int pager_write_pagelist(PgHdr *pList){
|
||||
if( pList->pgno<=pPager->dbSize ){
|
||||
CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
|
||||
TRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno);
|
||||
rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize);
|
||||
rc = sqlite3Io.xWrite(&pPager->fd, PGHDR_TO_DATA(pList),
|
||||
pPager->pageSize);
|
||||
CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
|
||||
TEST_INCR(pPager->nWrite);
|
||||
}
|
||||
@ -2290,10 +2288,10 @@ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
|
||||
*/
|
||||
static int hasHotJournal(Pager *pPager){
|
||||
if( !pPager->useJournal ) return 0;
|
||||
if( !sqlite3OsFileExists(pPager->zJournal) ) return 0;
|
||||
if( sqlite3OsCheckReservedLock(&pPager->fd) ) return 0;
|
||||
if( !sqlite3Io.xFileExists(pPager->zJournal) ) return 0;
|
||||
if( sqlite3Io.xCheckReservedLock(&pPager->fd) ) return 0;
|
||||
if( sqlite3pager_pagecount(pPager)==0 ){
|
||||
sqlite3OsDelete(pPager->zJournal);
|
||||
sqlite3Io.xDelete(pPager->zJournal);
|
||||
return 0;
|
||||
}else{
|
||||
return 1;
|
||||
@ -2370,9 +2368,9 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
** second process will get to this point in the code and fail to
|
||||
** obtain it's own EXCLUSIVE lock on the database file.
|
||||
*/
|
||||
rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK);
|
||||
rc = sqlite3Io.xLock(&pPager->fd, EXCLUSIVE_LOCK);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsUnlock(&pPager->fd, NO_LOCK);
|
||||
sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
|
||||
pPager->state = PAGER_UNLOCK;
|
||||
return rc;
|
||||
}
|
||||
@ -2386,9 +2384,9 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
** a write lock, so there is never any chance of two or more
|
||||
** processes opening the journal at the same time.
|
||||
*/
|
||||
rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
|
||||
rc = sqlite3Io.xOpenReadOnly(pPager->zJournal, &pPager->jfd);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsUnlock(&pPager->fd, NO_LOCK);
|
||||
sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
|
||||
pPager->state = PAGER_UNLOCK;
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
@ -2545,15 +2543,16 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||
}else{
|
||||
int rc;
|
||||
assert( MEMDB==0 );
|
||||
rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
||||
rc = sqlite3Io.xSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
|
||||
rc = sqlite3Io.xRead(&pPager->fd, PGHDR_TO_DATA(pPg),
|
||||
pPager->pageSize);
|
||||
}
|
||||
TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||
CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
|
||||
if( rc!=SQLITE_OK ){
|
||||
i64 fileSize;
|
||||
if( sqlite3OsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
|
||||
if( sqlite3Io.xFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
|
||||
|| fileSize>=pgno*pPager->pageSize ){
|
||||
sqlite3pager_unref(PGHDR_TO_DATA(pPg));
|
||||
return rc;
|
||||
@ -2675,7 +2674,8 @@ static int pager_open_journal(Pager *pPager){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto failed_to_open_journal;
|
||||
}
|
||||
rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile);
|
||||
rc = sqlite3Io.xOpenExclusive(pPager->zJournal, &pPager->jfd,
|
||||
pPager->tempFile);
|
||||
pPager->journalOff = 0;
|
||||
pPager->setMaster = 0;
|
||||
pPager->journalHdr = 0;
|
||||
@ -2684,7 +2684,7 @@ static int pager_open_journal(Pager *pPager){
|
||||
}
|
||||
SET_FULLSYNC(pPager->jfd, pPager->fullSync);
|
||||
SET_FULLSYNC(pPager->fd, pPager->fullSync);
|
||||
sqlite3OsOpenDirectory(pPager->zDirectory, &pPager->jfd);
|
||||
sqlite3Io.xOpenDirectory(pPager->zDirectory, &pPager->jfd);
|
||||
pPager->journalOpen = 1;
|
||||
pPager->journalStarted = 0;
|
||||
pPager->needSync = 0;
|
||||
@ -2712,7 +2712,7 @@ static int pager_open_journal(Pager *pPager){
|
||||
failed_to_open_journal:
|
||||
sqliteFree(pPager->aInJournal);
|
||||
pPager->aInJournal = 0;
|
||||
sqlite3OsUnlock(&pPager->fd, NO_LOCK);
|
||||
sqlite3Io.xUnlock(&pPager->fd, NO_LOCK);
|
||||
pPager->state = PAGER_UNLOCK;
|
||||
return rc;
|
||||
}
|
||||
@ -2756,7 +2756,7 @@ int sqlite3pager_begin(void *pData, int exFlag){
|
||||
pPager->state = PAGER_EXCLUSIVE;
|
||||
pPager->origDbSize = pPager->dbSize;
|
||||
}else{
|
||||
rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK);
|
||||
rc = sqlite3Io.xLock(&pPager->fd, RESERVED_LOCK);
|
||||
if( rc==SQLITE_OK ){
|
||||
pPager->state = PAGER_RESERVED;
|
||||
if( exFlag ){
|
||||
@ -2867,7 +2867,7 @@ int sqlite3pager_write(void *pData){
|
||||
store32bits(cksum, pPg, pPager->pageSize);
|
||||
szPg = pPager->pageSize+8;
|
||||
store32bits(pPg->pgno, pPg, -4);
|
||||
rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
|
||||
rc = sqlite3Io.xWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
|
||||
pPager->journalOff += szPg;
|
||||
TRACE4("JOURNAL %d page %d needSync=%d\n",
|
||||
PAGERID(pPager), pPg->pgno, pPg->needSync);
|
||||
@ -2916,7 +2916,8 @@ int sqlite3pager_write(void *pData){
|
||||
}else{
|
||||
store32bits(pPg->pgno, pPg, -4);
|
||||
CODEC(pPager, pData, pPg->pgno, 7);
|
||||
rc = sqlite3OsWrite(&pPager->stfd,((char*)pData)-4, pPager->pageSize+4);
|
||||
rc = sqlite3Io.xWrite(&pPager->stfd,((char*)pData)-4,
|
||||
pPager->pageSize+4);
|
||||
TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||
CODEC(pPager, pData, pPg->pgno, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@ -3119,7 +3120,7 @@ int sqlite3pager_commit(Pager *pPager){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( pPager->dirtyCache==0 ){
|
||||
/* Exit early (without doing the time-consuming sqlite3OsSync() calls)
|
||||
/* Exit early (without doing the time-consuming sqlite3Io.xSync() calls)
|
||||
** if there have been no changes to the database file. */
|
||||
assert( pPager->needSync==0 );
|
||||
rc = pager_unwritelock(pPager);
|
||||
@ -3278,11 +3279,11 @@ int sqlite3pager_stmt_begin(Pager *pPager){
|
||||
assert( pPager->journalOpen );
|
||||
pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 );
|
||||
if( pPager->aInStmt==0 ){
|
||||
sqlite3OsLock(&pPager->fd, SHARED_LOCK);
|
||||
sqlite3Io.xLock(&pPager->fd, SHARED_LOCK);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
rc = sqlite3OsFileSize(&pPager->jfd, &pPager->stmtJSize);
|
||||
rc = sqlite3Io.xFileSize(&pPager->jfd, &pPager->stmtJSize);
|
||||
if( rc ) goto stmt_begin_failed;
|
||||
assert( pPager->stmtJSize == pPager->journalOff );
|
||||
#endif
|
||||
@ -3315,8 +3316,8 @@ int sqlite3pager_stmt_commit(Pager *pPager){
|
||||
PgHdr *pPg, *pNext;
|
||||
TRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
|
||||
if( !MEMDB ){
|
||||
sqlite3OsSeek(&pPager->stfd, 0);
|
||||
/* sqlite3OsTruncate(&pPager->stfd, 0); */
|
||||
sqlite3Io.xSeek(&pPager->stfd, 0);
|
||||
/* sqlite3Io.xTruncate(&pPager->stfd, 0); */
|
||||
sqliteFree( pPager->aInStmt );
|
||||
pPager->aInStmt = 0;
|
||||
}
|
||||
@ -3519,7 +3520,7 @@ int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
|
||||
|
||||
/* Sync the database file. */
|
||||
if( !pPager->noSync ){
|
||||
rc = sqlite3OsSync(&pPager->fd, 0);
|
||||
rc = sqlite3Io.xSync(&pPager->fd, 0);
|
||||
}
|
||||
|
||||
pPager->state = PAGER_SYNCED;
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the PRAGMA command.
|
||||
**
|
||||
** $Id: pragma.c,v 1.103 2005/11/03 02:15:03 drh Exp $
|
||||
** $Id: pragma.c,v 1.104 2005/11/26 00:25:03 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -392,7 +392,7 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
}
|
||||
}else{
|
||||
if( zRight[0] && !sqlite3OsIsDirWritable(zRight) ){
|
||||
if( zRight[0] && !sqlite3Io.xIsDirWritable(zRight) ){
|
||||
sqlite3ErrorMsg(pParse, "not a writable directory");
|
||||
goto pragma_out;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** A TCL Interface to SQLite
|
||||
**
|
||||
** $Id: tclsqlite.c,v 1.133 2005/10/05 10:40:15 drh Exp $
|
||||
** $Id: tclsqlite.c,v 1.134 2005/11/26 00:25:03 drh Exp $
|
||||
*/
|
||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||
|
||||
@ -2059,6 +2059,7 @@ int TCLSH_MAIN(int argc, char **argv){
|
||||
extern int Sqlitetest3_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest4_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest5_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest6_Init(Tcl_Interp*);
|
||||
extern int Md5_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestsse_Init(Tcl_Interp*);
|
||||
|
||||
@ -2067,6 +2068,7 @@ int TCLSH_MAIN(int argc, char **argv){
|
||||
Sqlitetest3_Init(interp);
|
||||
Sqlitetest4_Init(interp);
|
||||
Sqlitetest5_Init(interp);
|
||||
Sqlitetest6_Init(interp);
|
||||
Md5_Init(interp);
|
||||
#ifdef SQLITE_SSE
|
||||
Sqlitetestsse_Init(interp);
|
||||
|
42
src/test1.c
42
src/test1.c
@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test1.c,v 1.165 2005/11/25 10:38:22 danielk1977 Exp $
|
||||
** $Id: test1.c,v 1.166 2005/11/26 00:25:03 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "tcl.h"
|
||||
@ -1412,29 +1412,6 @@ static int test_errstr(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int sqlite3_crashparams(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
#ifdef OS_TEST
|
||||
int delay;
|
||||
if( objc!=3 ) goto bad_args;
|
||||
if( Tcl_GetIntFromObj(interp, objv[1], &delay) ) return TCL_ERROR;
|
||||
sqlite3SetCrashParams(delay, Tcl_GetString(objv[2]));
|
||||
#endif
|
||||
return TCL_OK;
|
||||
|
||||
#ifdef OS_TEST
|
||||
bad_args:
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetStringFromObj(objv[0], 0), "<delay> <filename>", 0);
|
||||
return TCL_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Usage: breakpoint
|
||||
**
|
||||
@ -2464,7 +2441,7 @@ static int test_sqlite3OsOpenReadWrite(
|
||||
}
|
||||
|
||||
pFile = sqliteMalloc(sizeof(OsFile));
|
||||
rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), pFile, &dummy);
|
||||
rc = sqlite3Io.xOpenReadWrite(Tcl_GetString(objv[1]), pFile, &dummy);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteFree(pFile);
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
@ -2496,7 +2473,7 @@ static int test_sqlite3OsClose(
|
||||
if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3OsClose(pFile);
|
||||
rc = sqlite3Io.xClose(pFile);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
@ -2529,16 +2506,16 @@ static int test_sqlite3OsLock(
|
||||
}
|
||||
|
||||
if( 0==strcmp("SHARED", Tcl_GetString(objv[2])) ){
|
||||
rc = sqlite3OsLock(pFile, SHARED_LOCK);
|
||||
rc = sqlite3Io.xLock(pFile, SHARED_LOCK);
|
||||
}
|
||||
else if( 0==strcmp("RESERVED", Tcl_GetString(objv[2])) ){
|
||||
rc = sqlite3OsLock(pFile, RESERVED_LOCK);
|
||||
rc = sqlite3Io.xLock(pFile, RESERVED_LOCK);
|
||||
}
|
||||
else if( 0==strcmp("PENDING", Tcl_GetString(objv[2])) ){
|
||||
rc = sqlite3OsLock(pFile, PENDING_LOCK);
|
||||
rc = sqlite3Io.xLock(pFile, PENDING_LOCK);
|
||||
}
|
||||
else if( 0==strcmp("EXCLUSIVE", Tcl_GetString(objv[2])) ){
|
||||
rc = sqlite3OsLock(pFile, EXCLUSIVE_LOCK);
|
||||
rc = sqlite3Io.xLock(pFile, EXCLUSIVE_LOCK);
|
||||
}else{
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetString(objv[0]),
|
||||
@ -2574,7 +2551,7 @@ static int test_sqlite3OsUnlock(
|
||||
if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3OsUnlock(pFile, NO_LOCK);
|
||||
rc = sqlite3Io.xUnlock(pFile, NO_LOCK);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
@ -2594,7 +2571,7 @@ static int test_sqlite3OsTempFileName(
|
||||
char zFile[SQLITE_TEMPNAME_SIZE];
|
||||
int rc;
|
||||
|
||||
rc = sqlite3OsTempFileName(zFile);
|
||||
rc = sqlite3Io.xTempFileName(zFile);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
@ -3186,7 +3163,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "add_test_collate_needed", test_collate_needed, 0 },
|
||||
{ "add_test_function", test_function, 0 },
|
||||
#endif
|
||||
{ "sqlite3_crashparams", sqlite3_crashparams, 0 },
|
||||
{ "sqlite3_test_errstr", test_errstr, 0 },
|
||||
{ "tcl_variable_type", tcl_variable_type, 0 },
|
||||
};
|
||||
|
10
src/test2.c
10
src/test2.c
@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test2.c,v 1.35 2005/11/04 22:03:30 drh Exp $
|
||||
** $Id: test2.c,v 1.36 2005/11/26 00:25:04 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -533,20 +533,20 @@ static int fake_big_file(
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
|
||||
memset(&fd, 0, sizeof(fd));
|
||||
rc = sqlite3OsOpenReadWrite(argv[2], &fd, &readOnly);
|
||||
rc = sqlite3Io.xOpenReadWrite(argv[2], &fd, &readOnly);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
offset = n;
|
||||
offset *= 1024*1024;
|
||||
rc = sqlite3OsSeek(&fd, offset);
|
||||
rc = sqlite3Io.xSeek(&fd, offset);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, "seek failed: ", errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3OsWrite(&fd, "Hello, World!", 14);
|
||||
sqlite3OsClose(&fd);
|
||||
rc = sqlite3Io.xWrite(&fd, "Hello, World!", 14);
|
||||
sqlite3Io.xClose(&fd);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
|
478
src/test6.c
Normal file
478
src/test6.c
Normal file
@ -0,0 +1,478 @@
|
||||
/*
|
||||
** 2004 May 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file contains code that modified the OS layer in order to simulate
|
||||
** the effect on the database file of an OS crash or power failure. This
|
||||
** is used to test the ability of SQLite to recover from those situations.
|
||||
*/
|
||||
#if SQLITE_TEST /* This file is used for the testing only */
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
#include "tcl.h"
|
||||
|
||||
/*
|
||||
** A copy of the original sqlite3Io structure
|
||||
*/
|
||||
static struct sqlite3IoVtbl origIo;
|
||||
|
||||
/*
|
||||
** The pAux part of OsFile points to this structure.
|
||||
*/
|
||||
typedef struct OsTestFile OsTestFile;
|
||||
struct OsTestFile {
|
||||
u8 **apBlk; /* Array of blocks that have been written to. */
|
||||
int nBlk; /* Size of apBlock. */
|
||||
int nMaxWrite; /* Largest offset written to. */
|
||||
char *zName; /* File name */
|
||||
OsFile *pBase; /* Base class */
|
||||
OsTestFile *pNext; /* Next in a list of them all */
|
||||
};
|
||||
|
||||
/*
|
||||
** Size of a simulated disk block
|
||||
*/
|
||||
#define BLOCKSIZE 512
|
||||
#define BLOCK_OFFSET(x) ((x) * BLOCKSIZE)
|
||||
|
||||
|
||||
/*
|
||||
** The following variables control when a simulated crash occurs.
|
||||
**
|
||||
** If iCrashDelay is non-zero, then zCrashFile contains (full path) name of
|
||||
** a file that SQLite will call sqlite3OsSync() on. Each time this happens
|
||||
** iCrashDelay is decremented. If iCrashDelay is zero after being
|
||||
** decremented, a "crash" occurs during the sync() operation.
|
||||
**
|
||||
** In other words, a crash occurs the iCrashDelay'th time zCrashFile is
|
||||
** synced.
|
||||
*/
|
||||
static int iCrashDelay = 0;
|
||||
static char zCrashFile[500];
|
||||
|
||||
/*
|
||||
** Set the value of the two crash parameters.
|
||||
*/
|
||||
static void setCrashParams(int iDelay, char const *zFile){
|
||||
sqlite3OsEnterMutex();
|
||||
assert( strlen(zFile)<sizeof(zCrashFile) );
|
||||
strcpy(zCrashFile, zFile);
|
||||
iCrashDelay = iDelay;
|
||||
sqlite3OsLeaveMutex();
|
||||
}
|
||||
|
||||
/*
|
||||
** File zPath is being sync()ed. Return non-zero if this should
|
||||
** cause a crash.
|
||||
*/
|
||||
static int crashRequired(char const *zPath){
|
||||
int r;
|
||||
int n;
|
||||
sqlite3OsEnterMutex();
|
||||
n = strlen(zCrashFile);
|
||||
if( zCrashFile[n-1]=='*' ){
|
||||
n--;
|
||||
}else if( strlen(zPath)>n ){
|
||||
n = strlen(zPath);
|
||||
}
|
||||
r = 0;
|
||||
if( iCrashDelay>0 && strncmp(zPath, zCrashFile, n)==0 ){
|
||||
iCrashDelay--;
|
||||
if( iCrashDelay<=0 ){
|
||||
r = 1;
|
||||
}
|
||||
}
|
||||
sqlite3OsLeaveMutex();
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
** A list of all open files.
|
||||
*/
|
||||
static OsTestFile *pAllFiles = 0;
|
||||
|
||||
/*
|
||||
** Initialise the os_test.c specific fields of pFile.
|
||||
*/
|
||||
static void initFile(OsFile *id, char const *zName){
|
||||
OsTestFile *pFile = sqliteMalloc(sizeof(OsTestFile) + strlen(zName)+1);
|
||||
id->pAux = pFile;
|
||||
pFile->nMaxWrite = 0;
|
||||
pFile->nBlk = 0;
|
||||
pFile->apBlk = 0;
|
||||
pFile->zName = (char *)(&pFile[1]);
|
||||
strcpy(pFile->zName, zName);
|
||||
pFile->pBase = id;
|
||||
pFile->pNext = pAllFiles;
|
||||
pAllFiles = pFile;
|
||||
}
|
||||
|
||||
/*
|
||||
** Undo the work done by initFile. Delete the OsTestFile structure
|
||||
** and unlink the structure from the pAllFiles list.
|
||||
*/
|
||||
static void closeFile(OsFile *id){
|
||||
OsTestFile *pFile = (OsTestFile*)id->pAux;
|
||||
if( pFile==pAllFiles ){
|
||||
pAllFiles = pFile->pNext;
|
||||
}else{
|
||||
OsTestFile *p;
|
||||
for(p=pAllFiles; p->pNext!=pFile; p=p->pNext ){
|
||||
assert( p );
|
||||
}
|
||||
p->pNext = pFile->pNext;
|
||||
}
|
||||
sqliteFree(pFile);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current seek offset from the start of the file. This
|
||||
** is unix-only code.
|
||||
*/
|
||||
static i64 osTell(OsTestFile *pFile){
|
||||
return lseek(pFile->pBase->h, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
/*
|
||||
** Load block 'blk' into the cache of pFile.
|
||||
*/
|
||||
static int cacheBlock(OsTestFile *pFile, int blk){
|
||||
if( blk>=pFile->nBlk ){
|
||||
int n = ((pFile->nBlk * 2) + 100 + blk);
|
||||
/* if( pFile->nBlk==0 ){ printf("DIRTY %s\n", pFile->zName); } */
|
||||
pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*));
|
||||
if( !pFile->apBlk ) return SQLITE_NOMEM;
|
||||
memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*));
|
||||
pFile->nBlk = n;
|
||||
}
|
||||
|
||||
if( !pFile->apBlk[blk] ){
|
||||
i64 filesize;
|
||||
int rc;
|
||||
|
||||
u8 *p = sqliteMalloc(BLOCKSIZE);
|
||||
if( !p ) return SQLITE_NOMEM;
|
||||
pFile->apBlk[blk] = p;
|
||||
|
||||
rc = origIo.xFileSize(pFile->pBase, &filesize);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
if( BLOCK_OFFSET(blk)<filesize ){
|
||||
int len = BLOCKSIZE;
|
||||
rc = origIo.xSeek(pFile->pBase, blk*BLOCKSIZE);
|
||||
if( BLOCK_OFFSET(blk+1)>filesize ){
|
||||
len = filesize - BLOCK_OFFSET(blk);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
rc = origIo.xRead(pFile->pBase, p, len);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write the cache of pFile to disk. If crash is non-zero, randomly
|
||||
** skip blocks when writing. The cache is deleted before returning.
|
||||
*/
|
||||
static int writeCache2(OsTestFile *pFile, int crash){
|
||||
int i;
|
||||
int nMax = pFile->nMaxWrite;
|
||||
i64 offset;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
offset = osTell(pFile);
|
||||
for(i=0; i<pFile->nBlk; i++){
|
||||
u8 *p = pFile->apBlk[i];
|
||||
if( p ){
|
||||
int skip = 0;
|
||||
int trash = 0;
|
||||
if( crash ){
|
||||
char random;
|
||||
sqlite3Randomness(1, &random);
|
||||
if( random & 0x01 ){
|
||||
if( random & 0x02 ){
|
||||
trash = 1;
|
||||
#ifdef TRACE_WRITECACHE
|
||||
printf("Trashing block %d of %s\n", i, pFile->zName);
|
||||
#endif
|
||||
}else{
|
||||
skip = 1;
|
||||
#ifdef TRACE_WRITECACHE
|
||||
printf("Skiping block %d of %s\n", i, pFile->zName);
|
||||
#endif
|
||||
}
|
||||
}else{
|
||||
#ifdef TRACE_WRITECACHE
|
||||
printf("Writing block %d of %s\n", i, pFile->zName);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = origIo.xSeek(pFile->pBase, BLOCK_OFFSET(i));
|
||||
}
|
||||
if( rc==SQLITE_OK && !skip ){
|
||||
int len = BLOCKSIZE;
|
||||
if( BLOCK_OFFSET(i+1)>nMax ){
|
||||
len = nMax-BLOCK_OFFSET(i);
|
||||
}
|
||||
if( len>0 ){
|
||||
if( trash ){
|
||||
sqlite3Randomness(len, p);
|
||||
}
|
||||
rc = origIo.xWrite(pFile->pBase, p, len);
|
||||
}
|
||||
}
|
||||
sqliteFree(p);
|
||||
}
|
||||
}
|
||||
sqliteFree(pFile->apBlk);
|
||||
pFile->nBlk = 0;
|
||||
pFile->apBlk = 0;
|
||||
pFile->nMaxWrite = 0;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = origIo.xSeek(pFile->pBase, offset);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write the cache to disk.
|
||||
*/
|
||||
static int writeCache(OsTestFile *pFile){
|
||||
if( pFile->apBlk ){
|
||||
int c = crashRequired(pFile->zName);
|
||||
if( c ){
|
||||
OsTestFile *p;
|
||||
#ifdef TRACE_WRITECACHE
|
||||
printf("\nCrash during sync of %s\n", pFile->zName);
|
||||
#endif
|
||||
for(p=pAllFiles; p; p=p->pNext){
|
||||
writeCache2(p, 1);
|
||||
}
|
||||
exit(-1);
|
||||
}else{
|
||||
return writeCache2(pFile, 0);
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close the file.
|
||||
*/
|
||||
static int crashClose(OsFile *id){
|
||||
if( id->pAux ) return SQLITE_OK;
|
||||
if( id->isOpen ){
|
||||
/* printf("CLOSE %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
|
||||
writeCache((OsTestFile*)id->pAux);
|
||||
origIo.xClose(id);
|
||||
}
|
||||
closeFile(id);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int crashRead(OsFile *id, void *pBuf, int amt){
|
||||
i64 offset; /* The current offset from the start of the file */
|
||||
i64 end; /* The byte just past the last byte read */
|
||||
int blk; /* Block number the read starts on */
|
||||
int i;
|
||||
u8 *zCsr;
|
||||
int rc = SQLITE_OK;
|
||||
OsTestFile *pFile = (OsTestFile*)id->pAux;
|
||||
|
||||
offset = osTell(pFile);
|
||||
end = offset+amt;
|
||||
blk = (offset/BLOCKSIZE);
|
||||
|
||||
zCsr = (u8 *)pBuf;
|
||||
for(i=blk; i*BLOCKSIZE<end; i++){
|
||||
int off = 0;
|
||||
int len = 0;
|
||||
|
||||
|
||||
if( BLOCK_OFFSET(i) < offset ){
|
||||
off = offset-BLOCK_OFFSET(i);
|
||||
}
|
||||
len = BLOCKSIZE - off;
|
||||
if( BLOCK_OFFSET(i+1) > end ){
|
||||
len = len - (BLOCK_OFFSET(i+1)-end);
|
||||
}
|
||||
|
||||
if( i<pFile->nBlk && pFile->apBlk[i]){
|
||||
u8 *pBlk = pFile->apBlk[i];
|
||||
memcpy(zCsr, &pBlk[off], len);
|
||||
}else{
|
||||
rc = origIo.xSeek(id, BLOCK_OFFSET(i) + off);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
rc = origIo.xRead(id, zCsr, len);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
|
||||
zCsr += len;
|
||||
}
|
||||
assert( zCsr==&((u8 *)pBuf)[amt] );
|
||||
|
||||
rc = origIo.xSeek(id, end);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int crashWrite(OsFile *id, const void *pBuf, int amt){
|
||||
i64 offset; /* The current offset from the start of the file */
|
||||
i64 end; /* The byte just past the last byte written */
|
||||
int blk; /* Block number the write starts on */
|
||||
int i;
|
||||
const u8 *zCsr;
|
||||
int rc = SQLITE_OK;
|
||||
OsTestFile *pFile = (OsTestFile*)id->pAux;
|
||||
|
||||
offset = osTell(pFile);
|
||||
end = offset+amt;
|
||||
blk = (offset/BLOCKSIZE);
|
||||
|
||||
zCsr = (u8 *)pBuf;
|
||||
for(i=blk; i*BLOCKSIZE<end; i++){
|
||||
u8 *pBlk;
|
||||
int off = 0;
|
||||
int len = 0;
|
||||
|
||||
/* Make sure the block is in the cache */
|
||||
rc = cacheBlock(pFile, i);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
/* Write into the cache */
|
||||
pBlk = pFile->apBlk[i];
|
||||
assert( pBlk );
|
||||
|
||||
if( BLOCK_OFFSET(i) < offset ){
|
||||
off = offset-BLOCK_OFFSET(i);
|
||||
}
|
||||
len = BLOCKSIZE - off;
|
||||
if( BLOCK_OFFSET(i+1) > end ){
|
||||
len = len - (BLOCK_OFFSET(i+1)-end);
|
||||
}
|
||||
memcpy(&pBlk[off], zCsr, len);
|
||||
zCsr += len;
|
||||
}
|
||||
if( pFile->nMaxWrite<end ){
|
||||
pFile->nMaxWrite = end;
|
||||
}
|
||||
assert( zCsr==&((u8 *)pBuf)[amt] );
|
||||
|
||||
rc = origIo.xSeek(id, end);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync the file. First flush the write-cache to disk, then call the
|
||||
** real sync() function.
|
||||
*/
|
||||
static int crashSync(OsFile *id, int dataOnly){
|
||||
int rc;
|
||||
/* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
|
||||
rc = writeCache((OsTestFile*)id->pAux);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
rc = origIo.xSync(id, dataOnly);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate the file. Set the internal OsFile.nMaxWrite variable to the new
|
||||
** file size to ensure that nothing in the write-cache past this point
|
||||
** is written to disk.
|
||||
*/
|
||||
static int crashTruncate(OsFile *id, i64 nByte){
|
||||
OsTestFile *pFile = (OsTestFile*)id->pAux;
|
||||
pFile->nMaxWrite = nByte;
|
||||
return origIo.xTruncate(id, nByte);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the size of the file. If the cache contains a write that extended
|
||||
** the file, then return this size instead of the on-disk size.
|
||||
*/
|
||||
static int crashFileSize(OsFile *id, i64 *pSize){
|
||||
int rc = origIo.xFileSize(id, pSize);
|
||||
OsTestFile *pFile = (OsTestFile*)id->pAux;
|
||||
if( rc==SQLITE_OK && pSize && *pSize<pFile->nMaxWrite ){
|
||||
*pSize = pFile->nMaxWrite;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The three functions used to open files. All that is required is to
|
||||
** initialise the os_test.c specific fields and then call the corresponding
|
||||
** os_unix.c function to really open the file.
|
||||
*/
|
||||
static int crashOpenReadWrite(const char *zFilename, OsFile *id, int *pRdonly){
|
||||
initFile(id, zFilename);
|
||||
return origIo.xOpenReadWrite(zFilename, id, pRdonly);
|
||||
}
|
||||
static int crashOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||
initFile(id, zFilename);
|
||||
return origIo.xOpenExclusive(zFilename, id, delFlag);
|
||||
}
|
||||
static int crashOpenReadOnly(const char *zFilename, OsFile *id){
|
||||
initFile(id, zFilename);
|
||||
return origIo.xOpenReadOnly(zFilename, id);
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite_crashparams DELAY CRASHFILE
|
||||
**
|
||||
** This procedure implements a TCL command that enables crash testing
|
||||
** in testfixture. Once enabled, crash testing cannot be disabled.
|
||||
*/
|
||||
static int crashParamsObjCmd(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int delay;
|
||||
const char *zFile;
|
||||
int nFile;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DELAY CRASHFILE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIntFromObj(interp, objv[1], &delay) ) return TCL_ERROR;
|
||||
zFile = Tcl_GetStringFromObj(objv[2], &nFile);
|
||||
if( nFile>=sizeof(zCrashFile)-1 ){
|
||||
Tcl_AppendResult(interp, "crash file name too big", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
setCrashParams(delay, zFile);
|
||||
origIo = sqlite3Io;
|
||||
sqlite3Io.xRead = crashRead;
|
||||
sqlite3Io.xWrite = crashWrite;
|
||||
sqlite3Io.xClose = crashClose;
|
||||
sqlite3Io.xSync = crashSync;
|
||||
sqlite3Io.xTruncate = crashTruncate;
|
||||
sqlite3Io.xFileSize = crashFileSize;
|
||||
sqlite3Io.xOpenReadWrite = crashOpenReadWrite;
|
||||
sqlite3Io.xOpenExclusive = crashOpenExclusive;
|
||||
sqlite3Io.xOpenReadOnly = crashOpenReadOnly;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** This procedure registers the TCL procedures defined in this file.
|
||||
*/
|
||||
int Sqlitetest6_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_TEST */
|
@ -14,7 +14,7 @@
|
||||
** Most of the code in this file may be omitted by defining the
|
||||
** SQLITE_OMIT_VACUUM macro.
|
||||
**
|
||||
** $Id: vacuum.c,v 1.47 2005/11/04 22:03:30 drh Exp $
|
||||
** $Id: vacuum.c,v 1.48 2005/11/26 00:25:04 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -146,7 +146,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
do {
|
||||
zTemp[nFilename] = '-';
|
||||
randomName((unsigned char*)&zTemp[nFilename+1]);
|
||||
} while( sqlite3OsFileExists(zTemp) );
|
||||
} while( sqlite3Io.xFileExists(zTemp) );
|
||||
|
||||
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma
|
||||
** can be set to 'off' for this file, as it is not recovered if a crash
|
||||
@ -300,7 +300,7 @@ end_of_vacuum:
|
||||
rc = rc2;
|
||||
}
|
||||
if( zTemp ){
|
||||
sqlite3OsDelete(zTemp);
|
||||
sqlite3Io.xDelete(zTemp);
|
||||
sqliteFree(zTemp);
|
||||
}
|
||||
sqliteFree( zSql );
|
||||
|
@ -43,7 +43,7 @@
|
||||
** in this file for details. If in doubt, do not deviate from existing
|
||||
** commenting and indentation practices when changing or adding code.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.499 2005/11/24 14:34:36 drh Exp $
|
||||
** $Id: vdbe.c,v 1.500 2005/11/26 00:25:04 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -422,7 +422,7 @@ int sqlite3VdbeExec(
|
||||
}
|
||||
sqlite3VdbePrintOp(p->trace, pc, pOp);
|
||||
}
|
||||
if( p->trace==0 && pc==0 && sqlite3OsFileExists("vdbe_sqltrace") ){
|
||||
if( p->trace==0 && pc==0 && sqlite3Io.xFileExists("vdbe_sqltrace") ){
|
||||
sqlite3VdbePrintSql(p);
|
||||
}
|
||||
#endif
|
||||
|
@ -273,7 +273,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
|
||||
|
||||
/* If we never rollback a statement transaction, then statement
|
||||
** transactions are not needed. So change every OP_Statement
|
||||
** opcode into an OP_Noop. This avoid a call to sqlite3OsOpenExclusive()
|
||||
** opcode into an OP_Noop. This avoid a call to sqlite3Io.xOpenExclusive()
|
||||
** which can be expensive on some platforms.
|
||||
*/
|
||||
if( hasStatementBegin && !doesStatementRollback ){
|
||||
@ -755,7 +755,7 @@ void sqlite3VdbeMakeReady(
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( (p->db->flags & SQLITE_VdbeListing)!=0
|
||||
|| sqlite3OsFileExists("vdbe_explain")
|
||||
|| sqlite3Io.xFileExists("vdbe_explain")
|
||||
){
|
||||
int i;
|
||||
printf("VDBE Program Listing:\n");
|
||||
@ -764,7 +764,7 @@ void sqlite3VdbeMakeReady(
|
||||
sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
|
||||
}
|
||||
}
|
||||
if( sqlite3OsFileExists("vdbe_trace") ){
|
||||
if( sqlite3Io.xFileExists("vdbe_trace") ){
|
||||
p->trace = stdout;
|
||||
}
|
||||
#endif
|
||||
@ -978,11 +978,11 @@ static int vdbeCommit(sqlite3 *db){
|
||||
if( !zMaster ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
}while( sqlite3OsFileExists(zMaster) );
|
||||
}while( sqlite3Io.xFileExists(zMaster) );
|
||||
|
||||
/* Open the master journal. */
|
||||
memset(&master, 0, sizeof(master));
|
||||
rc = sqlite3OsOpenExclusive(zMaster, &master, 0);
|
||||
rc = sqlite3Io.xOpenExclusive(zMaster, &master, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteFree(zMaster);
|
||||
return rc;
|
||||
@ -1003,10 +1003,10 @@ static int vdbeCommit(sqlite3 *db){
|
||||
if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
|
||||
needSync = 1;
|
||||
}
|
||||
rc = sqlite3OsWrite(&master, zFile, strlen(zFile)+1);
|
||||
rc = sqlite3Io.xWrite(&master, zFile, strlen(zFile)+1);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsClose(&master);
|
||||
sqlite3OsDelete(zMaster);
|
||||
sqlite3Io.xClose(&master);
|
||||
sqlite3Io.xDelete(zMaster);
|
||||
sqliteFree(zMaster);
|
||||
return rc;
|
||||
}
|
||||
@ -1018,11 +1018,11 @@ static int vdbeCommit(sqlite3 *db){
|
||||
** the master journal file is store in so that it gets synced too.
|
||||
*/
|
||||
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
|
||||
rc = sqlite3OsOpenDirectory(zMainFile, &master);
|
||||
rc = sqlite3Io.xOpenDirectory(zMainFile, &master);
|
||||
if( rc!=SQLITE_OK ||
|
||||
(needSync && (rc=sqlite3OsSync(&master,0))!=SQLITE_OK) ){
|
||||
sqlite3OsClose(&master);
|
||||
sqlite3OsDelete(zMaster);
|
||||
(needSync && (rc=sqlite3Io.xSync(&master,0))!=SQLITE_OK) ){
|
||||
sqlite3Io.xClose(&master);
|
||||
sqlite3Io.xDelete(zMaster);
|
||||
sqliteFree(zMaster);
|
||||
return rc;
|
||||
}
|
||||
@ -1042,23 +1042,23 @@ static int vdbeCommit(sqlite3 *db){
|
||||
if( pBt && sqlite3BtreeIsInTrans(pBt) ){
|
||||
rc = sqlite3BtreeSync(pBt, zMaster);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3OsClose(&master);
|
||||
sqlite3Io.xClose(&master);
|
||||
sqliteFree(zMaster);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3OsClose(&master);
|
||||
sqlite3Io.xClose(&master);
|
||||
|
||||
/* Delete the master journal file. This commits the transaction. After
|
||||
** doing this the directory is synced again before any individual
|
||||
** transaction files are deleted.
|
||||
*/
|
||||
rc = sqlite3OsDelete(zMaster);
|
||||
rc = sqlite3Io.xDelete(zMaster);
|
||||
assert( rc==SQLITE_OK );
|
||||
sqliteFree(zMaster);
|
||||
zMaster = 0;
|
||||
rc = sqlite3OsSyncDirectory(zMainFile);
|
||||
rc = sqlite3Io.xSyncDirectory(zMainFile);
|
||||
if( rc!=SQLITE_OK ){
|
||||
/* This is not good. The master journal file has been deleted, but
|
||||
** the directory sync failed. There is no completely safe course of
|
||||
|
@ -12,15 +12,12 @@
|
||||
#
|
||||
# The focus of this file is testing the ability of the database to
|
||||
# uses its rollback journal to recover intact (no database corruption)
|
||||
# from a power failure during the middle of a COMMIT. The special test
|
||||
# module "crashtest" compiled with the special "os_test.c" backend is used.
|
||||
# The os_test.c simulates the kind of file corruption that can occur
|
||||
# when writes are happening at the moment of power loss.
|
||||
#
|
||||
# The special crash-test module with its os_test.c backend only works
|
||||
# on Unix.
|
||||
# from a power failure during the middle of a COMMIT. The OS interface
|
||||
# modules are overloaded in a separate instance of testfixture using
|
||||
# the modified I/O routines found in test6.c. These routines allow us
|
||||
# to simulate the kind of file damage that occurs after a power failure.
|
||||
#
|
||||
# $Id: crash.test,v 1.19 2005/09/17 17:05:19 drh Exp $
|
||||
# $Id: crash.test,v 1.20 2005/11/26 00:25:04 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -62,7 +59,7 @@ proc crashsql {crashdelay crashfile sql} {
|
||||
close $f
|
||||
|
||||
set r [catch {
|
||||
exec [file join . crashtest] crash.tcl >@stdout
|
||||
exec [info nameofexec] crash.tcl >@stdout
|
||||
} msg]
|
||||
lappend r $msg
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements some common TCL routines used for regression
|
||||
# testing the SQLite library
|
||||
#
|
||||
# $Id: tester.tcl,v 1.51 2005/11/04 22:03:30 drh Exp $
|
||||
# $Id: tester.tcl,v 1.52 2005/11/26 00:25:04 drh Exp $
|
||||
|
||||
# Make sure tclsqlite3 was compiled correctly. Abort now with an
|
||||
# error message if not.
|
||||
@ -281,7 +281,7 @@ proc crashsql {crashdelay crashfile sql} {
|
||||
close $f
|
||||
|
||||
set r [catch {
|
||||
exec [file join . crashtest] crash.tcl >@stdout
|
||||
exec [info nameofexec] crash.tcl >@stdout
|
||||
} msg]
|
||||
lappend r $msg
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user