diff --git a/manifest b/manifest index 71007d9576..5dc2612251 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Test\sthat\sit\sis\snow\spossible\sto\suse\sdifferent\sVFSs\sfor\stwo\sdatabases\sattached\sto\sa\ssingle\shandle. -D 2011-04-23T19:06:26.760 +C Merge\sthe\slatest\strunk\schanges\sinto\suri\sbranch. +D 2011-05-02T17:41:01.076 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 7a4d9524721d40ef9ee26f93f9bd6a51dba106f2 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -133,12 +133,12 @@ F src/delete.c 7a24fcc9a31664d145acb97ce56b6d9f249a25e4 F src/expr.c e3cf0957c6b8faaaf7386a3bc69e53c0dc9705be F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c a43ba8a005fb5efd1deeee06853e3a6120d46a91 -F src/func.c 3a8cb2fb2de3e3aed7f39106daf4878d9d17fcce +F src/func.c b9117e40975245b8504cf3625d7e321d8d4b63dc F src/global.c 29bfb85611dd816b04f10fba0ca910366e128d38 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c acfb89fe4a73d703e425e167bfcc72985f4299ae +F src/insert.c cdee360e5cea59db6c4a980e4360499631222af6 F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e @@ -162,8 +162,8 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9 F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 -F src/os_unix.c d7889a0f9389c8c2e1d3b380f5aa1256c22a90e8 -F src/os_win.c d149b9a7dfdd38de09afc054f8168cd3cd80630b +F src/os_unix.c 2c67d126874b78eb427371db4793f0e8fbc7448b +F src/os_win.c 4271f0bf733c0b45635ddcfb41c935573de8284c F src/pager.c 24b689bc3639d534f5fb292d2c68038b1e720527 F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1 F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58 @@ -239,7 +239,7 @@ F src/vdbe.c a7f8f72ae817f7f81a25be6e18d9a37e09b0649f F src/vdbe.h 8a675fefdf7119441fe817c800a9a52440c2e797 F src/vdbeInt.h fe8f58d305e629fff02f61f655aca1d299f1f6ae F src/vdbeapi.c e0e2672e0a96ae3f8575c8ecd02912a3e8a554a1 -F src/vdbeaux.c 9ae5074b19bdff2d8806a278533956fb281510d5 +F src/vdbeaux.c 5b8150112b490360fdf46f62f470a2ef75b0480a F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562 F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114 @@ -505,7 +505,7 @@ F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908 F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435 F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30 -F test/insert4.test c1469999a58e86a85b74df645a820f4cc7a8273b +F test/insert4.test b3e02648a5fc3075c29e13c369b5127bf859b5a2 F test/insert5.test 1f93cbe9742110119133d7e8e3ccfe6d7c249766 F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4 F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1 @@ -900,6 +900,7 @@ F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 +F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/lemon.c dfd81a51b6e27e469ba21d01a75ddf092d429027 F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309 @@ -912,7 +913,7 @@ F tool/omittest.tcl b1dd290c1596e0f31fd335160a74ec5dfea3df4a F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/shell1.test fee04fce1bf55e6e081523545fd4e0e83490ff8e +F tool/shell1.test 44705d6078b37f58853005d2ad5f1e67bc9dbbed F tool/shell2.test 5dc76b8005b465f420fed8241621da7513060ff3 F tool/shell3.test 4fad469e8003938426355afdf34155f08c587836 F tool/shell4.test 35f9c3d452b4e76d5013c63e1fd07478a62f14ce @@ -930,7 +931,7 @@ F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 68240e75e87a54cde93352b0ec364d34365a8170 -R 4f397b814ac53bbd808b171d5d8b418c +P 2af51f856c6203f836d8bb62b6b79b19554886e7 f55156c5194e85c47728b8a97fde3e5f0a5c9b56 +R 5b3361d8c251d725e8fb18c102b1e7f2 U dan -Z 87fa4f3faa1bbb8cd013b95e032b042b +Z ce77508d586b51f29df902539114b8b5 diff --git a/manifest.uuid b/manifest.uuid index ac2253e166..8258359950 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2af51f856c6203f836d8bb62b6b79b19554886e7 \ No newline at end of file +7fdd0786c7e0d66baf3aba4485128e16a4e5ea46 \ No newline at end of file diff --git a/src/func.c b/src/func.c index 6a4f7c09c3..0b9b600d79 100644 --- a/src/func.c +++ b/src/func.c @@ -774,6 +774,21 @@ static void sourceidFunc( sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC); } +/* +** Implementation of the sqlite_log() function. This is a wrapper around +** sqlite3_log(). The return value is NULL. The function exists purely for +** its side-effects. +*/ +static void errlogFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + UNUSED_PARAMETER(argc); + UNUSED_PARAMETER(context); + sqlite3_log(sqlite3_value_int(argv[0]), "%s", sqlite3_value_text(argv[1])); +} + /* ** Implementation of the sqlite_compileoption_used() function. ** The result is an integer that identifies if the compiler option @@ -1541,6 +1556,7 @@ void sqlite3RegisterGlobalFunctions(void){ FUNCTION(nullif, 2, 0, 1, nullifFunc ), FUNCTION(sqlite_version, 0, 0, 0, versionFunc ), FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), + FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), diff --git a/src/insert.c b/src/insert.c index 588a84f36d..02456e776f 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1734,6 +1734,18 @@ static int xferOptimization( return 0; /* Tables have different CHECK constraints. Ticket #2252 */ } #endif +#ifndef SQLITE_OMIT_FOREIGN_KEY + /* Disallow the transfer optimization if the destination table constains + ** any foreign key constraints. This is more restrictive than necessary. + ** But the main beneficiary of the transfer optimization is the VACUUM + ** command, and the VACUUM command disables foreign key constraints. So + ** the extra complication to make this rule less restrictive is probably + ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] + */ + if( (pParse->db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ + return 0; + } +#endif /* If we get this far, it means either: ** diff --git a/src/os_unix.c b/src/os_unix.c index 2d3a616373..a760e2c147 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -281,6 +281,18 @@ struct unixFile { #define threadid 0 #endif +/* +** Different Unix systems declare open() in different ways. Same use +** open(const char*,int,mode_t). Others use open(const char*,int,...). +** The difference is important when using a pointer to the function. +** +** The safest way to deal with the problem is to always use this wrapper +** which always has the same well-defined interface. +*/ +static int posixOpen(const char *zFile, int flags, int mode){ + return open(zFile, flags, mode); +} + /* ** Many system calls are accessed through pointer-to-functions so that ** they may be overridden at runtime to facilitate fault injection during @@ -292,8 +304,8 @@ static struct unix_syscall { sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ sqlite3_syscall_ptr pDefault; /* Default value */ } aSyscall[] = { - { "open", (sqlite3_syscall_ptr)open, 0 }, -#define osOpen ((int(*)(const char*,int,...))aSyscall[0].pCurrent) + { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, +#define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) { "close", (sqlite3_syscall_ptr)close, 0 }, #define osClose ((int(*)(int))aSyscall[1].pCurrent) diff --git a/src/os_win.c b/src/os_win.c index 654a964468..4e91f7ab32 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -286,7 +286,7 @@ char *sqlite3_win32_mbcs_to_utf8(const char *zFilename){ ** Convert UTF-8 to multibyte character string. Space to hold the ** returned string is obtained from malloc(). */ -static char *utf8ToMbcs(const char *zFilename){ +char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){ char *zFilenameMbcs; WCHAR *zTmpWide; @@ -1052,7 +1052,7 @@ static int unlockReadLock(winFile *pFile){ res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0); #endif } - if( res == 0 ){ + if( res==0 && GetLastError()!=ERROR_NOT_LOCKED ){ pFile->lastErrno = GetLastError(); winLogError(SQLITE_IOERR_UNLOCK, "unlockReadLock", pFile->zPath); } @@ -2004,7 +2004,7 @@ static void *convertUtf8Filename(const char *zFilename){ */ #if SQLITE_OS_WINCE==0 }else{ - zConverted = utf8ToMbcs(zFilename); + zConverted = sqlite3_win32_utf8_to_mbcs(zFilename); #endif } /* caller will handle out of memory */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 4d4bb224f9..b594e13277 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -2929,7 +2929,7 @@ int sqlite3VdbeRecordCompare( /* Compilers may complain that mem1.u.i is potentially uninitialized. ** We could initialize it, as shown here, to silence those complaints. - ** But in fact, mem1.u.i will never actually be used initialized, and doing + ** But in fact, mem1.u.i will never actually be used uninitialized, and doing ** the unnecessary initialization has a measurable negative performance ** impact, since this routine is a very high runner. And so, we choose ** to ignore the compiler warnings and leave this variable uninitialized. diff --git a/test/insert4.test b/test/insert4.test index 0b069e996d..44b428a1c7 100644 --- a/test/insert4.test +++ b/test/insert4.test @@ -326,4 +326,64 @@ do_test insert4-6.7 { } } {1 {constraint failed}} +# Ticket [6284df89debdfa61db8073e062908af0c9b6118e] +# Disable the xfer optimization if the destination table contains +# a foreign key constraint +# +ifcapable foreignkey { + do_test insert4-7.1 { + set ::sqlite3_xferopt_count 0 + execsql { + CREATE TABLE t7a(x INTEGER PRIMARY KEY); INSERT INTO t7a VALUES(123); + CREATE TABLE t7b(y INTEGER REFERENCES t7a); + CREATE TABLE t7c(z INT); INSERT INTO t7c VALUES(234); + INSERT INTO t7b SELECT * FROM t7c; + SELECT * FROM t7b; + } + } {234} + do_test insert4-7.2 { + set ::sqlite3_xferopt_count + } {1} + do_test insert4-7.3 { + set ::sqlite3_xferopt_count 0 + execsql { + DELETE FROM t7b; + PRAGMA foreign_keys=ON; + } + catchsql { + INSERT INTO t7b SELECT * FROM t7c; + } + } {1 {foreign key constraint failed}} + do_test insert4-7.4 { + execsql {SELECT * FROM t7b} + } {} + do_test insert4-7.5 { + set ::sqlite3_xferopt_count + } {0} + do_test insert4-7.6 { + set ::sqlite3_xferopt_count 0 + execsql { + DELETE FROM t7b; DELETE FROM t7c; + INSERT INTO t7c VALUES(123); + INSERT INTO t7b SELECT * FROM t7c; + SELECT * FROM t7b; + } + } {123} + do_test insert4-7.7 { + set ::sqlite3_xferopt_count + } {0} + do_test insert4-7.7 { + set ::sqlite3_xferopt_count 0 + execsql { + PRAGMA foreign_keys=OFF; + DELETE FROM t7b; + INSERT INTO t7b SELECT * FROM t7c; + SELECT * FROM t7b; + } + } {123} + do_test insert4-7.8 { + set ::sqlite3_xferopt_count + } {1} +} + finish_test diff --git a/tool/getlock.c b/tool/getlock.c new file mode 100644 index 0000000000..7eff04d7f9 --- /dev/null +++ b/tool/getlock.c @@ -0,0 +1,134 @@ +/* +** This utility program looks at an SQLite database and determines whether +** or not it is locked, the kind of lock, and who is holding this lock. +** +** This only works on unix when the posix advisory locking method is used +** (which is the default on unix) and when the PENDING_BYTE is in its +** usual place. +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +static void usage(const char *argv0){ + fprintf(stderr, "Usage: %s database\n", argv0); + exit(1); +} + +/* Check for a conflicting lock. If one is found, print an this +** on standard output using the format string given and return 1. +** If there are no conflicting locks, return 0. +*/ +static int isLocked( + int h, /* File descriptor to check */ + int type, /* F_RDLCK or F_WRLCK */ + unsigned int iOfst, /* First byte of the lock */ + unsigned int iCnt, /* Number of bytes in the lock range */ + const char *zType /* Type of lock */ +){ + struct flock lk; + + memset(&lk, 0, sizeof(lk)); + lk.l_type = type; + lk.l_whence = SEEK_SET; + lk.l_start = iOfst; + lk.l_len = iCnt; + if( fcntl(h, F_GETLK, &lk)==(-1) ){ + fprintf(stderr, "fcntl(%d) failed: errno=%d\n", h, errno); + exit(1); + } + if( lk.l_type==F_UNLCK ) return 0; + printf("%s lock held by %d\n", zType, (int)lk.l_pid); + return 1; +} + +/* +** Location of locking bytes in the database file +*/ +#define PENDING_BYTE (0x40000000) +#define RESERVED_BYTE (PENDING_BYTE+1) +#define SHARED_FIRST (PENDING_BYTE+2) +#define SHARED_SIZE 510 + +/* +** Lock locations for shared-memory locks used by WAL mode. +*/ +#define SHM_BASE 120 +#define SHM_WRITE SHM_BASE +#define SHM_CHECKPOINT (SHM_BASE+1) +#define SHM_RECOVER (SHM_BASE+2) +#define SHM_READ_FIRST (SHM_BASE+3) +#define SHM_READ_SIZE 5 + + +int main(int argc, char **argv){ + int hDb; /* File descriptor for the open database file */ + int hShm; /* File descriptor for WAL shared-memory file */ + char *zShm; /* Name of the shared-memory file for WAL mode */ + ssize_t got; /* Bytes read from header */ + int isWal; /* True if in WAL mode */ + int nName; /* Length of filename */ + unsigned char aHdr[100]; /* Database header */ + int nLock = 0; /* Number of locks held */ + int i; /* Loop counter */ + + if( argc!=2 ) usage(argv[0]); + hDb = open(argv[1], O_RDONLY, 0); + if( hDb<0 ){ + fprintf(stderr, "cannot open %s\n", argv[1]); + return 1; + } + + /* Make sure we are dealing with an database file */ + got = read(hDb, aHdr, 100); + if( got!=100 || memcmp(aHdr, "SQLite format 3",16)!=0 ){ + fprintf(stderr, "not an SQLite database: %s\n", argv[1]); + exit(1); + } + + /* First check for an exclusive lock */ + if( isLocked(hDb, F_RDLCK, SHARED_FIRST, SHARED_SIZE, "EXCLUSIVE") ){ + return 0; + } + isWal = aHdr[18]==2; + if( isWal==0 ){ + /* Rollback mode */ + if( isLocked(hDb, F_RDLCK, PENDING_BYTE, 1, "PENDING") ) return 0; + if( isLocked(hDb, F_RDLCK, RESERVED_BYTE, 1, "RESERVED") ) return 0; + if( isLocked(hDb, F_WRLCK, SHARED_FIRST, SHARED_SIZE, "SHARED") ){ + return 0; + } + }else{ + /* WAL mode */ + nName = (int)strlen(argv[1]); + zShm = malloc( nName + 100 ); + if( zShm==0 ){ + fprintf(stderr, "out of memory\n"); + exit(1); + } + memcpy(zShm, argv[1], nName); + memcpy(&zShm[nName], "-shm", 5); + hShm = open(zShm, O_RDONLY, 0); + if( hShm<0 ){ + fprintf(stderr, "cannot open %s\n", zShm); + return 1; + } + if( isLocked(hShm, F_RDLCK, SHM_RECOVER, 1, "WAL-RECOVERY") ){ + return 0; + } + nLock += isLocked(hShm, F_RDLCK, SHM_CHECKPOINT, 1, "WAL-CHECKPOINT"); + nLock += isLocked(hShm, F_RDLCK, SHM_WRITE, 1, "WAL-WRITE"); + for(i=0; i