From d6918657d8d50b7bec81f1c430709586ebc0c30f Mon Sep 17 00:00:00 2001 From: mistachkin Date: Tue, 29 Jul 2014 05:49:02 +0000 Subject: [PATCH 1/2] Enhancements and updates to the Win32 mutex subsystem. FossilOrigin-Name: 18984c321049a759f6619cfa17fb3f4e7b3e08ea --- manifest | 21 ++++---- manifest.uuid | 2 +- src/main.c | 2 +- src/mutex_w32.c | 139 +++++++++++++++++++++++++----------------------- src/os_win.c | 30 ++++++----- 5 files changed, 105 insertions(+), 89 deletions(-) diff --git a/manifest b/manifest index 4de9f86a27..632f5523e3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sunreachable\sbranch\sfrom\sthe\ssqlite3_value_numeric_type()\sinterface. -D 2014-07-26T20:12:56.006 +C Enhancements\sand\supdates\sto\sthe\sWin32\smutex\ssubsystem. +D 2014-07-29T05:49:02.604 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -189,7 +189,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303 -F src/main.c cfdb2aa5d248ff1af60227cc3f6d485ba86f92dc +F src/main.c 2c7647fd706cbb048e2b70429e552a7bf732d298 F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b @@ -201,14 +201,14 @@ F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553 F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc -F src/mutex_w32.c 9bcab6e699fdb20eae784237c36b299830fb3316 +F src/mutex_w32.c 45020ed78735a202ff14efcf19415d29f556f16d F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace F src/os.h 60d419395e32a8029fa380a80a3da2e9030f635e F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa F src/os_unix.c a7baf1b30f3c58ba20b813e01aab23b18ae44f85 -F src/os_win.c 8dbf6c11780fe2eb96c1f289e664d0c7b2911d37 +F src/os_win.c c29e3a80b47ebdbabd61fc3d4015e52d2654d8c5 F src/os_win.h 057344a6720b4c8405d9bd98f58cb37a6ee46c25 F src/pager.c f6bb1fa6cdf2062f2d8aec3e64db302bca519ab8 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 @@ -1184,7 +1184,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 413d7287977702fa651c0140bd5cf29021fe3e79 -R 882befeb8b61995267c9bc4311daa690 -U drh -Z 28fa8e103cbfa69958d1f03600e24fde +P 5350229b52b18a4961858a30538c5c75e5bd3048 +R de509ee2752907682d663ce7b389c5a6 +T *branch * winMutex +T *sym-winMutex * +T -sym-trunk * +U mistachkin +Z 9395c7aaf9a6a0a0988325332158758a diff --git a/manifest.uuid b/manifest.uuid index 58f6f007db..24c9f3e6fa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5350229b52b18a4961858a30538c5c75e5bd3048 \ No newline at end of file +18984c321049a759f6619cfa17fb3f4e7b3e08ea \ No newline at end of file diff --git a/src/main.c b/src/main.c index 904e0a4fc1..438ae7aeb5 100644 --- a/src/main.c +++ b/src/main.c @@ -1056,7 +1056,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){ ** Return a static string containing the name corresponding to the error code ** specified in the argument. */ -#if defined(SQLITE_TEST) +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) const char *sqlite3ErrName(int rc){ const char *zName = 0; int i, origRc = rc; diff --git a/src/mutex_w32.c b/src/mutex_w32.c index f43a152389..48f3bc6969 100644 --- a/src/mutex_w32.c +++ b/src/mutex_w32.c @@ -9,11 +9,16 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file contains the C functions that implement mutexes for win32 +** This file contains the C functions that implement mutexes for Win32. */ #include "sqliteInt.h" #if SQLITE_OS_WIN +/* +** Include code that is common to all os_*.c files +*/ +#include "os_common.h" + /* ** Include the header file for the Windows VFS. */ @@ -22,7 +27,7 @@ /* ** The code in this file is only used if we are compiling multithreaded -** on a win32 system. +** on a Win32 system. */ #ifdef SQLITE_MUTEX_W32 @@ -35,48 +40,22 @@ struct sqlite3_mutex { #ifdef SQLITE_DEBUG volatile int nRef; /* Number of enterances */ volatile DWORD owner; /* Thread holding this mutex */ - int trace; /* True to trace changes */ + volatile int trace; /* True to trace changes */ #endif }; -#define SQLITE_W32_MUTEX_INITIALIZER { 0 } -#ifdef SQLITE_DEBUG -#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 } -#else -#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 } -#endif /* -** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, -** or WinCE. Return false (zero) for Win95, Win98, or WinME. -** -** Here is an interesting observation: Win95, Win98, and WinME lack -** the LockFileEx() API. But we can still statically link against that -** API as long as we don't call it win running Win95/98/ME. A call to -** this routine is used to determine if the host is Win95/98/ME or -** WinNT/2K/XP so that we will know whether or not we can safely call -** the LockFileEx() API. -** -** mutexIsNT() is only used for the TryEnterCriticalSection() API call, -** which is only available if your application was compiled with -** _WIN32_WINNT defined to a value >= 0x0400. Currently, the only -** call to TryEnterCriticalSection() is #ifdef'ed out, so #ifdef -** this out as well. +** These are the initializer values used when declaring a "static" mutex +** on Win32. It should be noted that all mutexes require initialization +** on the Win32 platform. */ -#if 0 -#if SQLITE_OS_WINCE || SQLITE_OS_WINRT -# define mutexIsNT() (1) +#define SQLITE_W32_MUTEX_INITIALIZER { 0 } + +#ifdef SQLITE_DEBUG +#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \ + 0L, (DWORD)0, 0 } #else - static int mutexIsNT(void){ - static int osType = 0; - if( osType==0 ){ - OSVERSIONINFO sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - GetVersionEx(&sInfo); - osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; - } - return osType==2; - } -#endif /* SQLITE_OS_WINCE || SQLITE_OS_WINRT */ +#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 } #endif #ifdef SQLITE_DEBUG @@ -87,16 +66,17 @@ struct sqlite3_mutex { static int winMutexHeld(sqlite3_mutex *p){ return p->nRef!=0 && p->owner==GetCurrentThreadId(); } + static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){ return p->nRef==0 || p->owner!=tid; } + static int winMutexNotheld(sqlite3_mutex *p){ - DWORD tid = GetCurrentThreadId(); + DWORD tid = GetCurrentThreadId(); return winMutexNotheld2(p, tid); } #endif - /* ** Initialize and deinitialize the mutex subsystem. */ @@ -108,17 +88,20 @@ static sqlite3_mutex winMutex_staticMutexes[6] = { SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER }; + static int winMutex_isInit = 0; -/* As winMutexInit() and winMutexEnd() are called as part -** of the sqlite3_initialize and sqlite3_shutdown() -** processing, the "interlocked" magic is probably not -** strictly necessary. + +/* As winMutexInit() and winMutexEnd() are called as part of the +** sqlite3_initialize() and sqlite3_shutdown() processing, the +** "interlocked" magic used in this section may not strictly +** necessary. */ static LONG winMutex_lock = 0; +int sqlite3_win32_is_nt(void); /* os_win.c */ void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ -static int winMutexInit(void){ +static int winMutexInit(void){ /* The first to increment to 1 does actual initialization */ if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){ int i; @@ -131,16 +114,17 @@ static int winMutexInit(void){ } winMutex_isInit = 1; }else{ - /* Someone else is in the process of initing the static mutexes */ + /* Another thread is (in the process of) initializing the static + ** mutexes */ while( !winMutex_isInit ){ sqlite3_win32_sleep(1); } } - return SQLITE_OK; + return SQLITE_OK; } -static int winMutexEnd(void){ - /* The first to decrement to 0 does actual shutdown +static int winMutexEnd(void){ + /* The first to decrement to 0 does actual shutdown ** (which should be the last to shutdown.) */ if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){ if( winMutex_isInit==1 ){ @@ -151,7 +135,7 @@ static int winMutexEnd(void){ winMutex_isInit = 0; } } - return SQLITE_OK; + return SQLITE_OK; } /* @@ -192,7 +176,7 @@ static int winMutexEnd(void){ ** ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() -** returns a different mutex on every call. But for the static +** returns a different mutex on every call. But for the static ** mutex types, the same mutex is returned on every call that has ** the same type number. */ @@ -203,9 +187,12 @@ static sqlite3_mutex *winMutexAlloc(int iType){ case SQLITE_MUTEX_FAST: case SQLITE_MUTEX_RECURSIVE: { p = sqlite3MallocZero( sizeof(*p) ); - if( p ){ + if( p ){ #ifdef SQLITE_DEBUG p->id = iType; +#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC + p->trace = 1; +#endif #endif #if SQLITE_OS_WINRT InitializeCriticalSectionEx(&p->mutex, 0, 0); @@ -216,12 +203,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){ break; } default: { - assert( winMutex_isInit==1 ); assert( iType-2 >= 0 ); assert( iType-2 < ArraySize(winMutex_staticMutexes) ); + assert( winMutex_isInit==1 ); p = &winMutex_staticMutexes[iType-2]; #ifdef SQLITE_DEBUG p->id = iType; +#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC + p->trace = 1; +#endif #endif break; } @@ -237,8 +227,10 @@ static sqlite3_mutex *winMutexAlloc(int iType){ */ static void winMutexFree(sqlite3_mutex *p){ assert( p ); +#ifdef SQLITE_DEBUG assert( p->nRef==0 && p->owner==0 ); assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); +#endif DeleteCriticalSection(&p->mutex); sqlite3_free(p); } @@ -255,30 +247,38 @@ static void winMutexFree(sqlite3_mutex *p){ ** more than once, the behavior is undefined. */ static void winMutexEnter(sqlite3_mutex *p){ +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + DWORD tid = GetCurrentThreadId(); +#endif #ifdef SQLITE_DEBUG - DWORD tid = GetCurrentThreadId(); + assert( p ); assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); +#else + assert( p ); #endif EnterCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG assert( p->nRef>0 || p->owner==0 ); - p->owner = tid; + p->owner = tid; p->nRef++; if( p->trace ){ - printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", + tid, p, p->trace, p->nRef)); } #endif } + static int winMutexTry(sqlite3_mutex *p){ -#ifndef NDEBUG - DWORD tid = GetCurrentThreadId(); +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) + DWORD tid = GetCurrentThreadId(); #endif int rc = SQLITE_BUSY; + assert( p ); assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); /* ** The sqlite3_mutex_try() routine is very rarely used, and when it ** is used it is merely an optimization. So it is OK for it to always - ** fail. + ** fail. ** ** The TryEnterCriticalSection() interface is only available on WinNT. ** And some windows compilers complain if you try to use it without @@ -286,18 +286,21 @@ static int winMutexTry(sqlite3_mutex *p){ ** For that reason, we will omit this optimization for now. See ** ticket #2685. */ -#if 0 - if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){ +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 + if( sqlite3_win32_is_nt() && TryEnterCriticalSection(&p->mutex) ){ +#ifdef SQLITE_DEBUG p->owner = tid; p->nRef++; +#endif rc = SQLITE_OK; } #else UNUSED_PARAMETER(p); #endif #ifdef SQLITE_DEBUG - if( rc==SQLITE_OK && p->trace ){ - printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + if( p->trace ){ + OSTRACE(("TRY-MUTEX tid=%lu, mutex=%p (%d), owner=%lu, nRef=%d, rc=%s\n", + tid, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc))); } #endif return rc; @@ -310,8 +313,11 @@ static int winMutexTry(sqlite3_mutex *p){ ** is not currently allocated. SQLite will never do either. */ static void winMutexLeave(sqlite3_mutex *p){ -#ifndef NDEBUG +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) DWORD tid = GetCurrentThreadId(); +#endif + assert( p ); +#ifdef SQLITE_DEBUG assert( p->nRef>0 ); assert( p->owner==tid ); p->nRef--; @@ -321,7 +327,8 @@ static void winMutexLeave(sqlite3_mutex *p){ LeaveCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG if( p->trace ){ - printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); + OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", + tid, p, p->trace, p->nRef)); } #endif } @@ -343,7 +350,7 @@ sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ 0 #endif }; - return &sMutex; } + #endif /* SQLITE_MUTEX_W32 */ diff --git a/src/os_win.c b/src/os_win.c index 015b6c61da..842a4ad7cf 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -1298,22 +1298,28 @@ void sqlite3_win32_sleep(DWORD milliseconds){ #elif !defined(SQLITE_WIN32_HAS_WIDE) # define osIsNT() (0) #else - static int osIsNT(void){ - if( sqlite3_os_type==0 ){ +# define osIsNT() (sqlite3_win32_is_nt()) +#endif + +/* +** This function determines if the machine is running a version of Windows +** based on the NT kernel. +*/ +int sqlite3_win32_is_nt(void){ + if( sqlite3_os_type==0 ){ #if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8 - OSVERSIONINFOW sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - osGetVersionExW(&sInfo); + OSVERSIONINFOW sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + osGetVersionExW(&sInfo); #else - OSVERSIONINFOA sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - osGetVersionExA(&sInfo); + OSVERSIONINFOA sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + osGetVersionExA(&sInfo); #endif - sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; - } - return sqlite3_os_type==2; + sqlite3_os_type = (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1; } -#endif + return (sqlite3_os_type == 2); +} #ifdef SQLITE_WIN32_MALLOC /* From ac50232d0fb86ef6733ee697686aed3527ff693a Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 30 Jul 2014 13:56:48 +0000 Subject: [PATCH 2/2] Ensure that the correct number of columns in a UNIQUE index are checked for uniqueness, regardless of whether or not the original table has a ROWID or if the columns are NOT NULL, etc. Ticket [9a6daf340df99ba93c]. FossilOrigin-Name: 6b785e92f279cb65746834d5cd25594fd3333342 --- manifest | 19 ++++++------ manifest.uuid | 2 +- src/build.c | 2 +- src/vdbe.c | 12 ++++---- src/vdbesort.c | 13 ++++---- test/unique2.test | 78 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 102 insertions(+), 24 deletions(-) create mode 100644 test/unique2.test diff --git a/manifest b/manifest index 36b66e55d7..551a1332b7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhancements\sand\supdates\sto\sthe\sWin32\smutex\ssubsystem. -D 2014-07-29T19:54:03.929 +C Ensure\sthat\sthe\scorrect\snumber\sof\scolumns\sin\sa\sUNIQUE\sindex\sare\schecked\sfor\nuniqueness,\sregardless\sof\swhether\sor\snot\sthe\soriginal\stable\shas\sa\sROWID\sor\nif\sthe\scolumns\sare\sNOT\sNULL,\setc.\s\sTicket\s[9a6daf340df99ba93c]. +D 2014-07-30T13:56:48.415 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -170,7 +170,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btree.c b5531339cd826af46b9621e4a9323971a9380e12 F src/btree.h 4245a349bfe09611d7ff887dbc3a80cee8b7955a F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3 -F src/build.c 48f400fa14fd6add244b954ce7e223ce7ccacf0b +F src/build.c 7ba21d8f0f5f1e8b5a0ed21aab9be2b39d1af516 F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a @@ -283,14 +283,14 @@ F src/update.c 01564b3c430f6c7b0a35afaf7aba7987206fa3a5 F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05 F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c b127f05ff110c1f640b5aff98fa57d5028c8f2ee +F src/vdbe.c f87f77b0049cbef1fa68b331c3551d82b4d9fba4 F src/vdbe.h c63fad052c9e7388d551e556e119c0bcf6bebdf8 F src/vdbeInt.h f5513f2b5ac1e2c5128996c7ea23add256a301df F src/vdbeapi.c 24e40422382beb774daab11fe9fe9d37e8a04949 F src/vdbeaux.c ac063f36c929f88bf6cecdbcc413000e272265bb F src/vdbeblob.c 9205ce9d3b064d9600f8418a897fc88b5687d9ac F src/vdbemem.c d90a1e8acf8b63dc9d14cbbea12bfec6cec31394 -F src/vdbesort.c 44441d73b08b3a638dcdb725afffb87c6574ad27 +F src/vdbesort.c f7f5563bf7d4695ca8f3203f3bf9de96d04ed0b3 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a @@ -1041,6 +1041,7 @@ F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264 +F test/unique2.test 41e7f83c6827605991160a31380148a9fc5f1339 F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825 F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8 F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb @@ -1184,7 +1185,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 8b651d4d6cde7efbc0cc7155948f477477be100e 08c9a4ea6353900095a471365a8611a443f5f399 -R b75cbb8ba71bd17b820832cbd89e629a -U mistachkin -Z f55203ab4632e071cc6adc34ad558bc2 +P ca9868cdae19045dc522490b34dee0f14d928ebe +R aa3d0aadabff4023861d0c947293977e +U drh +Z 0e144877cde1d96e38c3dc4f9894f6d4 diff --git a/manifest.uuid b/manifest.uuid index 2526bc68aa..194b99221e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ca9868cdae19045dc522490b34dee0f14d928ebe \ No newline at end of file +6b785e92f279cb65746834d5cd25594fd3333342 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 27c9671da6..384802c533 100644 --- a/src/build.c +++ b/src/build.c @@ -2712,7 +2712,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord, - pKey->nField - pIndex->nKeyCol); VdbeCoverage(v); + pIndex->nKeyCol); VdbeCoverage(v); sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); }else{ addr2 = sqlite3VdbeCurrentAddr(v); diff --git a/src/vdbe.c b/src/vdbe.c index a00a1da836..52f0f3aa74 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -4271,12 +4271,12 @@ case OP_ResetCount: { } /* Opcode: SorterCompare P1 P2 P3 P4 -** Synopsis: if key(P1)!=rtrim(r[P3],P4) goto P2 +** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2 ** ** P1 is a sorter cursor. This instruction compares a prefix of the ** the record blob in register P3 against a prefix of the entry that -** the sorter cursor currently points to. The final P4 fields of both -** the P3 and sorter record are ignored. +** the sorter cursor currently points to. Only the first P4 fields +** of r[P3] and the sorter record are compared. ** ** If either P3 or the sorter contains a NULL in one of their significant ** fields (not counting the P4 fields at the end which are ignored) then @@ -4288,14 +4288,14 @@ case OP_ResetCount: { case OP_SorterCompare: { VdbeCursor *pC; int res; - int nIgnore; + int nKeyCol; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); assert( pOp->p4type==P4_INT32 ); pIn3 = &aMem[pOp->p3]; - nIgnore = pOp->p4.i; - rc = sqlite3VdbeSorterCompare(pC, pIn3, nIgnore, &res); + nKeyCol = pOp->p4.i; + rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res); VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2-1; diff --git a/src/vdbesort.c b/src/vdbesort.c index d3690244c4..6a5855f2ef 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -385,7 +385,7 @@ static int vdbeSorterIterInit( */ static void vdbeSorterCompare( const VdbeCursor *pCsr, /* Cursor object (for pKeyInfo) */ - int nIgnore, /* Ignore the last nIgnore fields */ + int nKeyCol, /* Num of columns. 0 means "all" */ const void *pKey1, int nKey1, /* Left side of comparison */ const void *pKey2, int nKey2, /* Right side of comparison */ int *pRes /* OUT: Result of comparison */ @@ -399,10 +399,9 @@ static void vdbeSorterCompare( sqlite3VdbeRecordUnpack(pKeyInfo, nKey2, pKey2, r2); } - if( nIgnore ){ - r2->nField = pKeyInfo->nField - nIgnore; - assert( r2->nField>0 ); - for(i=0; inField; i++){ + if( nKeyCol ){ + r2->nField = nKeyCol; + for(i=0; iaMem[i].flags & MEM_Null ){ *pRes = -1; return; @@ -1084,13 +1083,13 @@ int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){ int sqlite3VdbeSorterCompare( const VdbeCursor *pCsr, /* Sorter cursor */ Mem *pVal, /* Value to compare to current sorter key */ - int nIgnore, /* Ignore this many fields at the end */ + int nKeyCol, /* Only compare this many fields */ int *pRes /* OUT: Result of comparison */ ){ VdbeSorter *pSorter = pCsr->pSorter; void *pKey; int nKey; /* Sorter key to compare pVal with */ pKey = vdbeSorterRowkey(pSorter, &nKey); - vdbeSorterCompare(pCsr, nIgnore, pVal->z, pVal->n, pKey, nKey, pRes); + vdbeSorterCompare(pCsr, nKeyCol, pVal->z, pVal->n, pKey, nKey, pRes); return SQLITE_OK; } diff --git a/test/unique2.test b/test/unique2.test new file mode 100644 index 0000000000..6a320d4d7d --- /dev/null +++ b/test/unique2.test @@ -0,0 +1,78 @@ +# 2014-07-30 +# +# 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 implements regression tests for SQLite library. The +# focus of this file is testing the CREATE UNIQUE INDEX statement +# to verify that ticket 9a6daf340df99ba93c53bcf8fa83d9f28040d2a8 +# has been fixed: +# +# drh added on 2014-07-30 12:33:04: +# +# The CREATE UNIQUE INDEX on the third line below does not fail even +# though the x column values are not all unique. +# +# CREATE TABLE t1(x NOT NULL); +# INSERT INTO t1 VALUES(1),(2),(2),(3); +# CREATE UNIQUE INDEX t1x ON t1(x); +# +# If the index is created before the INSERT, then uniqueness is enforced +# at the point of the INSERT. Note that the NOT NULL on the indexed column +# seems to be required in order to exhibit this bug. +# +# "PRAGMA integrity_check" does not detect the resulting malformed database. +# That might be considered a separate issue. +# +# Bisecting shows that this problem was introduced by the addition of +# WITHOUT ROWID support in version 3.8.2, specifically in check-in +# [c80e229dd9c1230] on 2013-11-07. This problem was reported on the mailing +# list by Pavel Pimenov. and primary keys, and the UNIQUE constraint +# on table columns +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +foreach {id sql} { + 1 {CREATE TABLE t1(x TEXT PRIMARY KEY, y NOT NULL) WITHOUT ROWID} + 2 {CREATE TABLE t1(x TEXT PRIMARY KEY, y NOT NULL)} + 3 {CREATE TABLE t1(x TEXT PRIMARY KEY, y) WITHOUT ROWID} + 4 {CREATE TABLE t1(x TEXT PRIMARY KEY, y)} +} { + do_test $id.1 { + db eval {DROP TABLE IF EXISTS t1} + db eval $sql + db eval {INSERT INTO t1(x,y) VALUES(1,1),(2,2),(3,2),(4,3)} + } {} + do_test $id.2 { + catchsql {CREATE UNIQUE INDEX t1y ON t1(y)} + } {1 {UNIQUE constraint failed: t1.y}} +} + +foreach {id sql} { + 5 {CREATE TABLE t1(w,x,y NOT NULL,z NOT NULL,PRIMARY KEY(w,x)) WITHOUT ROWID} + 6 {CREATE TABLE t1(w,x,y NOT NULL,z NOT NULL,PRIMARY KEY(w,x))} + 7 {CREATE TABLE t1(w,x,y NOT NULL,z,PRIMARY KEY(w,x)) WITHOUT ROWID} + 8 {CREATE TABLE t1(w,x,y NOT NULL,z,PRIMARY KEY(w,x))} + 9 {CREATE TABLE t1(w,x,y,z NOT NULL,PRIMARY KEY(w,x)) WITHOUT ROWID} + 10 {CREATE TABLE t1(w,x,y,z NOT NULL,PRIMARY KEY(w,x))} + 11 {CREATE TABLE t1(w,x,y,z,PRIMARY KEY(w,x)) WITHOUT ROWID} + 12 {CREATE TABLE t1(w,x,y,z,PRIMARY KEY(w,x))} +} { + do_test $id.1 { + db eval {DROP TABLE IF EXISTS t1} + db eval $sql + db eval {INSERT INTO t1(w,x,y,z) VALUES(1,2,3,4),(2,3,3,4)} + } {} + do_test $id.2 { + catchsql {CREATE UNIQUE INDEX t1yz ON t1(y,z)} + } {1 {UNIQUE constraint failed: t1.y, t1.z}} +} + +finish_test