From a1a8298c2e89d45be0865b3bead1faf83b926705 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 30 Jul 2014 15:43:05 +0000 Subject: [PATCH 01/25] Add the "eForce" parameter to the sqlite3_multiplex_shutdown() entry point in test_multiplex.c. Shutdown is forced if true. Shutdown is not done if there are pending database connections and eForce is false, but an error log entry is made instead. FossilOrigin-Name: c7303d0139f7e7f4fa7060b52942e6c6c6d4b622 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/test_multiplex.c | 21 +++++++++++++++------ src/test_multiplex.h | 2 +- test/multiplex.test | 10 ++++++++++ 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 551a1332b7..ac3ca46634 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -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 +C Add\sthe\s"eForce"\sparameter\sto\sthe\ssqlite3_multiplex_shutdown()\sentry\spoint\nin\stest_multiplex.c.\s\sShutdown\sis\sforced\sif\strue.\s\sShutdown\sis\snot\sdone\sif\nthere\sare\spending\sdatabase\sconnections\sand\seForce\sis\sfalse,\sbut\san\serror\slog\nentry\sis\smade\sinstead. +D 2014-07-30T15:43:05.568 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -257,8 +257,8 @@ F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64 F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4 F src/test_malloc.c 1ff5b1243d96124c9a180f3b89424820a1f337f3 -F src/test_multiplex.c 9f304bf04170c91c0318238d512df2da039eb1c8 -F src/test_multiplex.h 110a8c4d356e0aa464ca8730375608a9a0b61ae1 +F src/test_multiplex.c ca90057438b63bf0840ebb84d0ef050624519a76 +F src/test_multiplex.h c08e4e8f8651f0c5e0509b138ff4d5b43ed1f5d3 F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f F src/test_onefile.c 0396f220561f3b4eedc450cef26d40c593c69a25 F src/test_osinst.c 3d0340bc31a9f3d8a3547e0272373e80f78dde25 @@ -719,7 +719,7 @@ F test/mmap1.test 93d167b328255cbe6679fe1e1a23be1b1197d07b F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3 -F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256 +F test/multiplex.test 4a0d07a2490dc958e6b676a6825cf761be33d869 F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41 @@ -1185,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 ca9868cdae19045dc522490b34dee0f14d928ebe -R aa3d0aadabff4023861d0c947293977e +P 6b785e92f279cb65746834d5cd25594fd3333342 +R 91be173298089741f719dedf8b4f59f4 U drh -Z 0e144877cde1d96e38c3dc4f9894f6d4 +Z 69b6c3f54a5e9094db9af1965ce3b4cb diff --git a/manifest.uuid b/manifest.uuid index 194b99221e..2ce81d04f9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6b785e92f279cb65746834d5cd25594fd3333342 \ No newline at end of file +c7303d0139f7e7f4fa7060b52942e6c6c6d4b622 \ No newline at end of file diff --git a/src/test_multiplex.c b/src/test_multiplex.c index 45a1edfbbe..427cc65ad7 100644 --- a/src/test_multiplex.c +++ b/src/test_multiplex.c @@ -1176,14 +1176,20 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){ ** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while ** shutting down in order to free all remaining multiplex groups. */ -int sqlite3_multiplex_shutdown(void){ +int sqlite3_multiplex_shutdown(int eForce){ + int rc = SQLITE_OK; if( gMultiplex.isInitialized==0 ) return SQLITE_MISUSE; - if( gMultiplex.pGroups ) return SQLITE_MISUSE; + if( gMultiplex.pGroups ){ + sqlite3_log(SQLITE_MISUSE, "sqlite3_multiplex_shutdown() called " + "while database connections are still open"); + if( !eForce ) return SQLITE_MISUSE; + rc = SQLITE_MISUSE; + } gMultiplex.isInitialized = 0; sqlite3_mutex_free(gMultiplex.pMutex); sqlite3_vfs_unregister(&gMultiplex.sThisVfs); memset(&gMultiplex, 0, sizeof(gMultiplex)); - return SQLITE_OK; + return rc; } /***************************** Test Code ***********************************/ @@ -1236,13 +1242,16 @@ static int test_multiplex_shutdown( UNUSED_PARAMETER(clientData); - if( objc!=1 ){ - Tcl_WrongNumArgs(interp, 1, objv, ""); + if( objc==2 && strcmp(Tcl_GetString(objv[1]),"-force")!=0 ){ + objc = 3; + } + if( (objc!=1 && objc!=2) ){ + Tcl_WrongNumArgs(interp, 1, objv, "?-force?"); return TCL_ERROR; } /* Call sqlite3_multiplex_shutdown() */ - rc = sqlite3_multiplex_shutdown(); + rc = sqlite3_multiplex_shutdown(objc==2); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); return TCL_OK; diff --git a/src/test_multiplex.h b/src/test_multiplex.h index 9fe2f0f2b2..d973e4af27 100644 --- a/src/test_multiplex.h +++ b/src/test_multiplex.h @@ -90,7 +90,7 @@ extern int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefaul ** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while ** shutting down in order to free all remaining multiplex groups. */ -extern int sqlite3_multiplex_shutdown(void); +extern int sqlite3_multiplex_shutdown(int eForce); #ifdef __cplusplus } /* End of the 'extern "C"' block */ diff --git a/test/multiplex.test b/test/multiplex.test index 32c87d9a52..55fab013c4 100644 --- a/test/multiplex.test +++ b/test/multiplex.test @@ -68,6 +68,12 @@ proc multiplex_delete {name} { } db close +sqlite3_shutdown +test_sqlite3_log xLog +proc xLog {error_code msg} { + lappend ::log $error_code $msg +} +unset -nocomplain log multiplex_delete test.db multiplex_delete test2.db @@ -188,12 +194,16 @@ do_test multiplex-2.3.1 { } {} +unset -nocomplain ::log do_test multiplex-2.4.1 { sqlite3_multiplex_shutdown } {SQLITE_MISUSE} do_test multiplex-2.4.2 { execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } } {} +do_test multiplex-2.4.3 { + set ::log +} {SQLITE_MISUSE {sqlite3_multiplex_shutdown() called while database connections are still open}} do_test multiplex-2.4.4 { file size [multiplex_name test.x 0] } {7168} do_test multiplex-2.4.5 { db close From d42d0bed943d1c807eed4b69256f4211665cee24 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 30 Jul 2014 21:10:12 +0000 Subject: [PATCH 02/25] Add three new static mutexes for use by the application. This is a partial import of changes from the threads branch. FossilOrigin-Name: 3aad01960f92c5e77dba64ac1a6c6b063378fb97 --- manifest | 20 +++---- manifest.uuid | 2 +- src/mutex.c | 2 +- src/mutex_noop.c | 2 +- src/mutex_unix.c | 8 ++- src/mutex_w32.c | 153 ++++++++++++++++++++++++----------------------- src/sqlite.h.in | 9 ++- 7 files changed, 105 insertions(+), 91 deletions(-) diff --git a/manifest b/manifest index ac3ca46634..276387fbe1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\s"eForce"\sparameter\sto\sthe\ssqlite3_multiplex_shutdown()\sentry\spoint\nin\stest_multiplex.c.\s\sShutdown\sis\sforced\sif\strue.\s\sShutdown\sis\snot\sdone\sif\nthere\sare\spending\sdatabase\sconnections\sand\seForce\sis\sfalse,\sbut\san\serror\slog\nentry\sis\smade\sinstead. -D 2014-07-30T15:43:05.568 +C Add\sthree\snew\sstatic\smutexes\sfor\suse\sby\sthe\sapplication.\s\sThis\sis\sa\spartial\nimport\sof\schanges\sfrom\sthe\sthreads\sbranch. +D 2014-07-30T21:10:12.606 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -197,11 +197,11 @@ F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534 F src/mem5.c 74670012946c4adc8a6ad84d03acc80959c3e529 F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785 -F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc +F src/mutex.c 84a073c9a23a8d7bdd2ea832522d1730df18812c F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea -F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553 -F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc -F src/mutex_w32.c 45020ed78735a202ff14efcf19415d29f556f16d +F src/mutex_noop.c f3f09fd7a2eb4287cfc799753ffc30380e7b71a1 +F src/mutex_unix.c 1b10d5413dfc794364a8adf3eb3a192926b43fa3 +F src/mutex_w32.c 92e8ead41598a289c93ac64dfd5e78820c4dabc1 F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace F src/os.h 60d419395e32a8029fa380a80a3da2e9030f635e @@ -224,7 +224,7 @@ F src/resolve.c 5fc110baeacf120a73fe34e103f052632ff11a02 F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be F src/select.c 6762c62e11b504aa014edceab8886495165e3a77 F src/shell.c 191129c3f7a9cf241aea90ff6a6be3e74d3767f0 -F src/sqlite.h.in 5967719136e14183b2573ba619993438e2b9856e +F src/sqlite.h.in 9bbc5815c73b0e77e68b5275481a5e3e7814a804 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc F src/sqliteInt.h 068e42f41a09ce6b9edbe194ac8a470ab53145df @@ -1185,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 6b785e92f279cb65746834d5cd25594fd3333342 -R 91be173298089741f719dedf8b4f59f4 +P c7303d0139f7e7f4fa7060b52942e6c6c6d4b622 +R 9a0604d781d4eb725027fc152740bd2b U drh -Z 69b6c3f54a5e9094db9af1965ce3b4cb +Z b2c6542aa553cebe25ffe186e01d871a diff --git a/manifest.uuid b/manifest.uuid index 2ce81d04f9..03e9ad26fa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c7303d0139f7e7f4fa7060b52942e6c6c6d4b622 \ No newline at end of file +3aad01960f92c5e77dba64ac1a6c6b063378fb97 \ No newline at end of file diff --git a/src/mutex.c b/src/mutex.c index b567e7c27e..bad5a7c113 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -81,7 +81,7 @@ int sqlite3MutexEnd(void){ */ sqlite3_mutex *sqlite3_mutex_alloc(int id){ #ifndef SQLITE_OMIT_AUTOINIT - if( sqlite3_initialize() ) return 0; + if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0; #endif return sqlite3GlobalConfig.mutex.xMutexAlloc(id); } diff --git a/src/mutex_noop.c b/src/mutex_noop.c index 456e82a25e..1a900c225a 100644 --- a/src/mutex_noop.c +++ b/src/mutex_noop.c @@ -107,7 +107,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; } ** that means that a mutex could not be allocated. */ static sqlite3_mutex *debugMutexAlloc(int id){ - static sqlite3_debug_mutex aStatic[6]; + static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_APP3 - 1]; sqlite3_debug_mutex *pNew = 0; switch( id ){ case SQLITE_MUTEX_FAST: diff --git a/src/mutex_unix.c b/src/mutex_unix.c index eca7295831..c8663144e8 100644 --- a/src/mutex_unix.c +++ b/src/mutex_unix.c @@ -96,10 +96,13 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; } **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MASTER **
  • SQLITE_MUTEX_STATIC_MEM -**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU **
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 +**
  • SQLITE_MUTEX_STATIC_APP3 ** ** ** The first two constants cause sqlite3_mutex_alloc() to create @@ -133,6 +136,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){ SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER }; sqlite3_mutex *p; diff --git a/src/mutex_w32.c b/src/mutex_w32.c index 48f3bc6969..78d1a6fba4 100644 --- a/src/mutex_w32.c +++ b/src/mutex_w32.c @@ -9,16 +9,11 @@ ** 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. */ @@ -27,7 +22,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 @@ -40,24 +35,50 @@ struct sqlite3_mutex { #ifdef SQLITE_DEBUG volatile int nRef; /* Number of enterances */ volatile DWORD owner; /* Thread holding this mutex */ - volatile int trace; /* True to trace changes */ + int trace; /* True to trace changes */ #endif }; - -/* -** 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. -*/ #define SQLITE_W32_MUTEX_INITIALIZER { 0 } - #ifdef SQLITE_DEBUG -#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \ - 0L, (DWORD)0, 0 } +#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. +*/ +#if 0 +#if SQLITE_OS_WINCE || SQLITE_OS_WINRT +# define mutexIsNT() (1) +#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 */ +#endif + #ifdef SQLITE_DEBUG /* ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are @@ -66,21 +87,23 @@ 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. */ -static sqlite3_mutex winMutex_staticMutexes[6] = { +static sqlite3_mutex winMutex_staticMutexes[] = { + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, + SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, SQLITE3_MUTEX_INITIALIZER, @@ -88,20 +111,17 @@ 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 used in this section may not strictly -** necessary. +/* As winMutexInit() and winMutexEnd() are called as part +** of the sqlite3_initialize and sqlite3_shutdown() +** processing, the "interlocked" magic is probably 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; @@ -114,17 +134,16 @@ static int winMutexInit(void){ } winMutex_isInit = 1; }else{ - /* Another thread is (in the process of) initializing the static - ** mutexes */ + /* Someone else is in the process of initing 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 ){ @@ -135,7 +154,7 @@ static int winMutexEnd(void){ winMutex_isInit = 0; } } - return SQLITE_OK; + return SQLITE_OK; } /* @@ -150,10 +169,13 @@ static int winMutexEnd(void){ **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MASTER **
  • SQLITE_MUTEX_STATIC_MEM -**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU **
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 +**
  • SQLITE_MUTEX_STATIC_APP3 ** ** ** The first two constants cause sqlite3_mutex_alloc() to create @@ -176,7 +198,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. */ @@ -187,12 +209,9 @@ 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); @@ -203,15 +222,12 @@ 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; } @@ -227,10 +243,9 @@ 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 + assert( winMutex_isInit==1 ); DeleteCriticalSection(&p->mutex); sqlite3_free(p); } @@ -247,38 +262,31 @@ 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 - assert( p ); + DWORD tid = GetCurrentThreadId(); assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) ); -#else - assert( p ); #endif + assert( winMutex_isInit==1 ); EnterCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG assert( p->nRef>0 || p->owner==0 ); - p->owner = tid; + p->owner = tid; p->nRef++; if( p->trace ){ - OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", - tid, p, p->trace, p->nRef)); + printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); } #endif } - static int winMutexTry(sqlite3_mutex *p){ -#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) - DWORD tid = GetCurrentThreadId(); +#ifndef NDEBUG + 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,21 +294,19 @@ static int winMutexTry(sqlite3_mutex *p){ ** For that reason, we will omit this optimization for now. See ** ticket #2685. */ -#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 - if( sqlite3_win32_is_nt() && TryEnterCriticalSection(&p->mutex) ){ -#ifdef SQLITE_DEBUG +#if 0 + assert( winMutex_isInit==1 ); + if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){ p->owner = tid; p->nRef++; -#endif rc = SQLITE_OK; } #else UNUSED_PARAMETER(p); #endif #ifdef SQLITE_DEBUG - 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))); + if( rc==SQLITE_OK && p->trace ){ + printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); } #endif return rc; @@ -313,22 +319,19 @@ static int winMutexTry(sqlite3_mutex *p){ ** is not currently allocated. SQLite will never do either. */ static void winMutexLeave(sqlite3_mutex *p){ -#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) +#ifndef NDEBUG DWORD tid = GetCurrentThreadId(); -#endif - assert( p ); -#ifdef SQLITE_DEBUG assert( p->nRef>0 ); assert( p->owner==tid ); p->nRef--; if( p->nRef==0 ) p->owner = 0; assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); #endif + assert( winMutex_isInit==1 ); LeaveCriticalSection(&p->mutex); #ifdef SQLITE_DEBUG if( p->trace ){ - OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n", - tid, p, p->trace, p->nRef)); + printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef); } #endif } @@ -350,7 +353,7 @@ sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ 0 #endif }; + return &sMutex; } - #endif /* SQLITE_MUTEX_W32 */ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 8d51632285..8470d9e8c0 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -5875,10 +5875,12 @@ int sqlite3_vfs_unregister(sqlite3_vfs*); **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MASTER **
  • SQLITE_MUTEX_STATIC_MEM -**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_OPEN **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU -**
  • SQLITE_MUTEX_STATIC_LRU2 +**
  • SQLITE_MUTEX_STATIC_PMEM +**
  • SQLITE_MUTEX_STATIC_APP1 +**
  • SQLITE_MUTEX_STATIC_APP2 ** )^ ** ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) @@ -6082,6 +6084,9 @@ int sqlite3_mutex_notheld(sqlite3_mutex*); #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ +#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */ +#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */ /* ** CAPI3REF: Retrieve the mutex for a database connection From 0174ffa976f7a042a5ae1adaf58b1b125d5f0eb1 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Wed, 30 Jul 2014 23:11:16 +0000 Subject: [PATCH 03/25] Re-integrate the recent changes from the 'winMutex' branch back into the Win32 mutex subsystem. FossilOrigin-Name: 5360ecb0b8891d0c27f3f02d81b6c7b548361a10 --- manifest | 14 ++--- manifest.uuid | 2 +- src/mutex_w32.c | 138 +++++++++++++++++++++++++----------------------- 3 files changed, 80 insertions(+), 74 deletions(-) diff --git a/manifest b/manifest index 276387fbe1..c1369a4aa5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthree\snew\sstatic\smutexes\sfor\suse\sby\sthe\sapplication.\s\sThis\sis\sa\spartial\nimport\sof\schanges\sfrom\sthe\sthreads\sbranch. -D 2014-07-30T21:10:12.606 +C Re-integrate\sthe\srecent\schanges\sfrom\sthe\s'winMutex'\sbranch\sback\sinto\sthe\sWin32\smutex\ssubsystem. +D 2014-07-30T23:11:16.516 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -201,7 +201,7 @@ F src/mutex.c 84a073c9a23a8d7bdd2ea832522d1730df18812c F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea F src/mutex_noop.c f3f09fd7a2eb4287cfc799753ffc30380e7b71a1 F src/mutex_unix.c 1b10d5413dfc794364a8adf3eb3a192926b43fa3 -F src/mutex_w32.c 92e8ead41598a289c93ac64dfd5e78820c4dabc1 +F src/mutex_w32.c 08890085b81ce181d2cbc6fc2636e3444ae30b27 F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace F src/os.h 60d419395e32a8029fa380a80a3da2e9030f635e @@ -1185,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 c7303d0139f7e7f4fa7060b52942e6c6c6d4b622 -R 9a0604d781d4eb725027fc152740bd2b -U drh -Z b2c6542aa553cebe25ffe186e01d871a +P 3aad01960f92c5e77dba64ac1a6c6b063378fb97 +R 30d9c6511ca3c35312cef2a09e79ecbc +U mistachkin +Z c0143953af6d35d374b1fbf6a22594a7 diff --git a/manifest.uuid b/manifest.uuid index 03e9ad26fa..ab5604951f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3aad01960f92c5e77dba64ac1a6c6b063378fb97 \ No newline at end of file +5360ecb0b8891d0c27f3f02d81b6c7b548361a10 \ No newline at end of file diff --git a/src/mutex_w32.c b/src/mutex_w32.c index 78d1a6fba4..c34f28f0e4 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. */ @@ -111,17 +91,19 @@ static sqlite3_mutex winMutex_staticMutexes[] = { 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 the winMutexInit() and winMutexEnd() functions are called as part +** of the sqlite3_initialize() and sqlite3_shutdown() processing, the +** "interlocked" magic used here is probably 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; @@ -134,16 +116,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 ){ @@ -154,7 +137,7 @@ static int winMutexEnd(void){ winMutex_isInit = 0; } } - return SQLITE_OK; + return SQLITE_OK; } /* @@ -198,7 +181,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. */ @@ -209,9 +192,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); @@ -222,12 +208,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; } @@ -243,8 +232,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 assert( winMutex_isInit==1 ); DeleteCriticalSection(&p->mutex); sqlite3_free(p); @@ -262,31 +253,39 @@ 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 assert( winMutex_isInit==1 ); 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 @@ -294,19 +293,22 @@ static int winMutexTry(sqlite3_mutex *p){ ** For that reason, we will omit this optimization for now. See ** ticket #2685. */ -#if 0 +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 assert( winMutex_isInit==1 ); - if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){ + 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; @@ -319,8 +321,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--; @@ -331,7 +336,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 } @@ -353,7 +359,7 @@ sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ 0 #endif }; - return &sMutex; } + #endif /* SQLITE_MUTEX_W32 */ From 4387006c18f99a63fffbed12ce30a0a099999c18 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 31 Jul 2014 15:44:44 +0000 Subject: [PATCH 04/25] Deactivate the DISTINCT in a SELECT on the right-hand side of an IN operator, since it should not make any difference in the output but dues consume extra memory and CPU time. FossilOrigin-Name: f4cb53651b1e352fae7378878b830a902bcd9248 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/expr.c | 11 +++++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index c1369a4aa5..240778ae2c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Re-integrate\sthe\srecent\schanges\sfrom\sthe\s'winMutex'\sbranch\sback\sinto\sthe\sWin32\smutex\ssubsystem. -D 2014-07-30T23:11:16.516 +C Deactivate\sthe\sDISTINCT\sin\sa\sSELECT\son\sthe\sright-hand\sside\sof\san\sIN\soperator,\nsince\sit\sshould\snot\smake\sany\sdifference\sin\sthe\soutput\sbut\sdues\sconsume\sextra\nmemory\sand\sCPU\stime. +D 2014-07-31T15:44:44.199 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c b989d07fc7c8780fff77365a4fc59881223e340c +F src/expr.c 77ca517a25a589f8088df88ace671e1c1d7dd3de F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c a549cff9fe8b736cdae21650ea0af6de29b77619 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -1185,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 3aad01960f92c5e77dba64ac1a6c6b063378fb97 -R 30d9c6511ca3c35312cef2a09e79ecbc -U mistachkin -Z c0143953af6d35d374b1fbf6a22594a7 +P 5360ecb0b8891d0c27f3f02d81b6c7b548361a10 +R fa406e6fe8ac4b7f1ba9a949d0399141 +U drh +Z ae156d6c18fec68cfd3675b456914b76 diff --git a/manifest.uuid b/manifest.uuid index ab5604951f..1f35b44ebe 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5360ecb0b8891d0c27f3f02d81b6c7b548361a10 \ No newline at end of file +f4cb53651b1e352fae7378878b830a902bcd9248 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 72286dfdf9..94647e5148 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1624,7 +1624,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ } if( eType==0 ){ - /* Could not found an existing table or index to use as the RHS b-tree. + /* Could not find an existing table or index to use as the RHS b-tree. ** We will have to generate an ephemeral table to do the job. */ u32 savedNQueryLoop = pParse->nQueryLoop; @@ -1754,6 +1754,7 @@ int sqlite3CodeSubselect( ** Generate code to write the results of the select into the temporary ** table allocated and opened above. */ + Select *pSelect = pExpr->x.pSelect; SelectDest dest; ExprList *pEList; @@ -1761,13 +1762,15 @@ int sqlite3CodeSubselect( sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); dest.affSdst = (u8)affinity; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); - pExpr->x.pSelect->iLimit = 0; + pSelect->iLimit = 0; + testcase( pSelect->selFlags & SF_Distinct ); + pSelect->selFlags &= ~SF_Distinct; testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */ - if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){ + if( sqlite3Select(pParse, pSelect, &dest) ){ sqlite3KeyInfoUnref(pKeyInfo); return 0; } - pEList = pExpr->x.pSelect->pEList; + pEList = pSelect->pEList; assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ assert( pEList!=0 ); assert( pEList->nExpr>0 ); From e8559837e68730202854a92235c5abd7bd5e97b2 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 31 Jul 2014 17:35:40 +0000 Subject: [PATCH 05/25] Fix a leaked statement handle in pager2.test. FossilOrigin-Name: 47457b0488abcbec2137abf706c1d677563b9ea5 --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/tester.tcl | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 240778ae2c..c990fe1cc9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Deactivate\sthe\sDISTINCT\sin\sa\sSELECT\son\sthe\sright-hand\sside\sof\san\sIN\soperator,\nsince\sit\sshould\snot\smake\sany\sdifference\sin\sthe\soutput\sbut\sdues\sconsume\sextra\nmemory\sand\sCPU\stime. -D 2014-07-31T15:44:44.199 +C Fix\sa\sleaked\sstatement\shandle\sin\spager2.test. +D 2014-07-31T17:35:40.036 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -863,7 +863,7 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 -F test/tester.tcl f31bea1483ea1d39620f982130026e76f872d744 +F test/tester.tcl b4ff83a8b069633f4aca788236d10a7086112a49 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1185,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 5360ecb0b8891d0c27f3f02d81b6c7b548361a10 -R fa406e6fe8ac4b7f1ba9a949d0399141 -U drh -Z ae156d6c18fec68cfd3675b456914b76 +P f4cb53651b1e352fae7378878b830a902bcd9248 +R 6cb5ac9ad4e6d98c300e9ffde83ac7f3 +U dan +Z 2d65f06df1c6f3ff1350a732b5e2220f diff --git a/manifest.uuid b/manifest.uuid index 1f35b44ebe..0528abb823 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f4cb53651b1e352fae7378878b830a902bcd9248 \ No newline at end of file +47457b0488abcbec2137abf706c1d677563b9ea5 \ No newline at end of file diff --git a/test/tester.tcl b/test/tester.tcl index 1c4e93937c..3bf92f2b4f 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -863,6 +863,7 @@ proc speed_trial_summary {name} { # proc finish_test {} { catch {db close} + catch {db1 close} catch {db2 close} catch {db3 close} if {0==[info exists ::SLAVE]} { finalize_testing } From f6296cafc54513b5072c1a9aa14f554ce7cc22be Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 31 Jul 2014 18:14:37 +0000 Subject: [PATCH 06/25] Add a missing call to "test_sqlite3_log" to multiplex.test. FossilOrigin-Name: 0708f9df23a325349f658741358c5994b5c4c873 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/multiplex.test | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index c990fe1cc9..13634c500c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sleaked\sstatement\shandle\sin\spager2.test. -D 2014-07-31T17:35:40.036 +C Add\sa\smissing\scall\sto\s"test_sqlite3_log"\sto\smultiplex.test. +D 2014-07-31T18:14:37.512 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -719,7 +719,7 @@ F test/mmap1.test 93d167b328255cbe6679fe1e1a23be1b1197d07b F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3 -F test/multiplex.test 4a0d07a2490dc958e6b676a6825cf761be33d869 +F test/multiplex.test efd015ca0b5b4a57dc9535b8feb1273eebeadb60 F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41 @@ -1185,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 f4cb53651b1e352fae7378878b830a902bcd9248 -R 6cb5ac9ad4e6d98c300e9ffde83ac7f3 +P 47457b0488abcbec2137abf706c1d677563b9ea5 +R 40079bb444b74388b9936aaa1a8a8059 U dan -Z 2d65f06df1c6f3ff1350a732b5e2220f +Z a0b960eb92c17485651b9cbc9a7c3b70 diff --git a/manifest.uuid b/manifest.uuid index 0528abb823..fa6a4ad3e8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -47457b0488abcbec2137abf706c1d677563b9ea5 \ No newline at end of file +0708f9df23a325349f658741358c5994b5c4c873 \ No newline at end of file diff --git a/test/multiplex.test b/test/multiplex.test index 55fab013c4..5db56f264a 100644 --- a/test/multiplex.test +++ b/test/multiplex.test @@ -593,5 +593,9 @@ do_test multiplex-6.99 { } +catch { db close } catch { sqlite3_multiplex_shutdown } +sqlite3_shutdown +test_sqlite3_log +sqlite3_initialize finish_test From 202cb641898ae45a957a1543e2e014335601bbe9 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Thu, 31 Jul 2014 18:54:01 +0000 Subject: [PATCH 07/25] Optimizations to the OS sub-type checking in the Win32 VFS. FossilOrigin-Name: 1e5489faff093d6a8e538061e45532f9050e9459 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/mutex_w32.c | 10 ++++++++-- src/os_win.c | 20 +++++++++++++------- src/test1.c | 4 ++-- 5 files changed, 33 insertions(+), 21 deletions(-) diff --git a/manifest b/manifest index 13634c500c..498fa5f658 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\smissing\scall\sto\s"test_sqlite3_log"\sto\smultiplex.test. -D 2014-07-31T18:14:37.512 +C Optimizations\sto\sthe\sOS\ssub-type\schecking\sin\sthe\sWin32\sVFS. +D 2014-07-31T18:54:01.916 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -201,14 +201,14 @@ F src/mutex.c 84a073c9a23a8d7bdd2ea832522d1730df18812c F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea F src/mutex_noop.c f3f09fd7a2eb4287cfc799753ffc30380e7b71a1 F src/mutex_unix.c 1b10d5413dfc794364a8adf3eb3a192926b43fa3 -F src/mutex_w32.c 08890085b81ce181d2cbc6fc2636e3444ae30b27 +F src/mutex_w32.c c50939b72368f1cfbddb58520372081a50558548 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 c29e3a80b47ebdbabd61fc3d4015e52d2654d8c5 +F src/os_win.c c67bec43e5dadde8029470ab7b7825ccc9abe578 F src/os_win.h 057344a6720b4c8405d9bd98f58cb37a6ee46c25 F src/pager.c f6bb1fa6cdf2062f2d8aec3e64db302bca519ab8 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 @@ -232,7 +232,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c e87c99e28a145943666b51b212dacae35fcea0bd -F src/test1.c 3c8bc491d2f8de5adbbf306533cefc343c733927 +F src/test1.c 14409a611e9c27c6c522c610bbff5561f05c1558 F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -1185,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 47457b0488abcbec2137abf706c1d677563b9ea5 -R 40079bb444b74388b9936aaa1a8a8059 -U dan -Z a0b960eb92c17485651b9cbc9a7c3b70 +P 0708f9df23a325349f658741358c5994b5c4c873 +R 33905802a155aabab7e0415ce706b3b1 +U mistachkin +Z f67dc40e0d7f1ad1a9a6019eb7b3fb85 diff --git a/manifest.uuid b/manifest.uuid index fa6a4ad3e8..42ebb3917e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0708f9df23a325349f658741358c5994b5c4c873 \ No newline at end of file +1e5489faff093d6a8e538061e45532f9050e9459 \ No newline at end of file diff --git a/src/mutex_w32.c b/src/mutex_w32.c index c34f28f0e4..218342d2b9 100644 --- a/src/mutex_w32.c +++ b/src/mutex_w32.c @@ -93,12 +93,13 @@ static sqlite3_mutex winMutex_staticMutexes[] = { }; static int winMutex_isInit = 0; +static int winMutex_isNt = -1; /* <0 means "need to query" */ /* As the winMutexInit() and winMutexEnd() functions are called as part ** of the sqlite3_initialize() and sqlite3_shutdown() processing, the ** "interlocked" magic used here is probably not strictly necessary. */ -static LONG winMutex_lock = 0; +static LONG volatile winMutex_lock = 0; int sqlite3_win32_is_nt(void); /* os_win.c */ void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */ @@ -295,7 +296,12 @@ static int winMutexTry(sqlite3_mutex *p){ */ #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 assert( winMutex_isInit==1 ); - if( sqlite3_win32_is_nt() && TryEnterCriticalSection(&p->mutex) ){ + assert( winMutex_isNt>=-1 && winMutex_isNt<=1 ); + if( winMutex_isNt<0 ){ + winMutex_isNt = sqlite3_win32_is_nt(); + } + assert( winMutex_isNt==0 || winMutex_isNt==1 ); + if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){ #ifdef SQLITE_DEBUG p->owner = tid; p->nRef++; diff --git a/src/os_win.c b/src/os_win.c index 842a4ad7cf..fd2997206c 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -414,10 +414,10 @@ const sqlite3_mem_methods *sqlite3MemGetWin32(void); ** can manually set this value to 1 to emulate Win98 behavior. */ #ifdef SQLITE_TEST -int sqlite3_os_type = 0; +LONG volatile sqlite3_os_type = 0; #elif !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_HAS_WIDE) -static int sqlite3_os_type = 0; +static LONG volatile sqlite3_os_type = 0; #endif #ifndef SYSCALL @@ -1048,6 +1048,11 @@ static struct win_syscall { #define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent) + { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, + +#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG volatile*, \ + LONG,LONG))aSyscall[76].pCurrent) + }; /* End of the overrideable system calls */ /* @@ -1298,7 +1303,7 @@ void sqlite3_win32_sleep(DWORD milliseconds){ #elif !defined(SQLITE_WIN32_HAS_WIDE) # define osIsNT() (0) #else -# define osIsNT() (sqlite3_win32_is_nt()) +# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt()) #endif /* @@ -1306,7 +1311,7 @@ void sqlite3_win32_sleep(DWORD milliseconds){ ** based on the NT kernel. */ int sqlite3_win32_is_nt(void){ - if( sqlite3_os_type==0 ){ + if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ #if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8 OSVERSIONINFOW sInfo; sInfo.dwOSVersionInfoSize = sizeof(sInfo); @@ -1316,9 +1321,10 @@ int sqlite3_win32_is_nt(void){ sInfo.dwOSVersionInfoSize = sizeof(sInfo); osGetVersionExA(&sInfo); #endif - sqlite3_os_type = (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1; + osInterlockedCompareExchange(&sqlite3_os_type, + (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0); } - return (sqlite3_os_type == 2); + return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2; } #ifdef SQLITE_WIN32_MALLOC @@ -5475,7 +5481,7 @@ int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==76 ); + assert( ArraySize(aSyscall)==77 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); diff --git a/src/test1.c b/src/test1.c index 8d2249cbb8..56487f6abb 100644 --- a/src/test1.c +++ b/src/test1.c @@ -6581,7 +6581,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_pager_writedb_count; extern int sqlite3_pager_writej_count; #if SQLITE_OS_WIN - extern int sqlite3_os_type; + extern LONG volatile sqlite3_os_type; #endif #ifdef SQLITE_DEBUG extern int sqlite3WhereTrace; @@ -6639,7 +6639,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ #endif #if SQLITE_OS_WIN Tcl_LinkVar(interp, "sqlite_os_type", - (char*)&sqlite3_os_type, TCL_LINK_INT); + (char*)&sqlite3_os_type, TCL_LINK_LONG); #endif #ifdef SQLITE_TEST { From 37e08081f3da7ceab00ff4db996510f924de931a Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 31 Jul 2014 20:16:08 +0000 Subject: [PATCH 08/25] Omit a pointless OP_Null when processing a value-list RHS of an IN operator where the LHS is a rowid. FossilOrigin-Name: 1361450a9dfe9476e8df98f370a3695752252245 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/expr.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 498fa5f658..8e34956aba 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Optimizations\sto\sthe\sOS\ssub-type\schecking\sin\sthe\sWin32\sVFS. -D 2014-07-31T18:54:01.916 +C Omit\sa\spointless\sOP_Null\swhen\sprocessing\sa\svalue-list\sRHS\sof\san\sIN\soperator\nwhere\sthe\sLHS\sis\sa\srowid. +D 2014-07-31T20:16:08.031 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 77ca517a25a589f8088df88ace671e1c1d7dd3de +F src/expr.c 0e2a6c1cd3b752bea188a92bd826a2304c79e7bf F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c a549cff9fe8b736cdae21650ea0af6de29b77619 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -1185,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 0708f9df23a325349f658741358c5994b5c4c873 -R 33905802a155aabab7e0415ce706b3b1 -U mistachkin -Z f67dc40e0d7f1ad1a9a6019eb7b3fb85 +P 1e5489faff093d6a8e538061e45532f9050e9459 +R cbfd634bf9c7df43faab424574b6f5df +U drh +Z a5f816e75181f7c6a373a521ba2c396b diff --git a/manifest.uuid b/manifest.uuid index 42ebb3917e..13453542e7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1e5489faff093d6a8e538061e45532f9050e9459 \ No newline at end of file +1361450a9dfe9476e8df98f370a3695752252245 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 94647e5148..aa55ff7af2 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1801,7 +1801,7 @@ int sqlite3CodeSubselect( /* Loop through each expression in . */ r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp2(v, OP_Null, 0, r2); + if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2); for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ Expr *pE2 = pItem->pExpr; int iValToIns; From 5f1d1d9c870f2377d6907ec05df3c6d38d75cd57 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 31 Jul 2014 22:59:04 +0000 Subject: [PATCH 09/25] Refactoring: Change "pIndex->onError!=OE_None" to use a macro: "IsUniqueIndex(pIndex)". Easier to understand that way. FossilOrigin-Name: e75b26ee357bb3d3c1a539b05d633ebf314726d7 --- manifest | 26 +++++++++++++------------- manifest.uuid | 2 +- src/analyze.c | 2 +- src/build.c | 8 ++++---- src/expr.c | 2 +- src/fkey.c | 2 +- src/insert.c | 2 +- src/pragma.c | 2 +- src/sqliteInt.h | 3 +++ src/where.c | 8 ++++---- 10 files changed, 30 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 8e34956aba..7cd7515a7e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Omit\sa\spointless\sOP_Null\swhen\sprocessing\sa\svalue-list\sRHS\sof\san\sIN\soperator\nwhere\sthe\sLHS\sis\sa\srowid. -D 2014-07-31T20:16:08.031 +C Refactoring:\s\sChange\s"pIndex->onError!=OE_None"\sto\suse\sa\smacro:\n"IsUniqueIndex(pIndex)".\s\sEasier\sto\sunderstand\sthat\sway. +D 2014-07-31T22:59:04.121 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -161,7 +161,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1 -F src/analyze.c de34a73b86db9dc3a16beef12cc5573c50223956 +F src/analyze.c f98a351908da29f7b44741cfeb9eb20dda648ba0 F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53 @@ -170,21 +170,21 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btree.c b5531339cd826af46b9621e4a9323971a9380e12 F src/btree.h 4245a349bfe09611d7ff887dbc3a80cee8b7955a F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3 -F src/build.c 7ba21d8f0f5f1e8b5a0ed21aab9be2b39d1af516 +F src/build.c c67a915cd5aabda9ac170f2af8ea25434476b66f F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 0e2a6c1cd3b752bea188a92bd826a2304c79e7bf +F src/expr.c 3be0e9f90bb1c475a99a821a11eecde53ecefc1d F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb -F src/fkey.c a549cff9fe8b736cdae21650ea0af6de29b77619 +F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc F src/global.c 1e4bd956dc2f608f87d2a929abc4a20db65f30e4 F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c a038daeadfb818aaadafa854f40f5623b6929d84 +F src/insert.c 991e4964e9295da3993e2c0f81c7faf642371848 F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b @@ -216,7 +216,7 @@ F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0 F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c -F src/pragma.c 30f3b2ac09fef58320375d78e0e18b976198fc69 +F src/pragma.c f9268bd5fa072afb3a174149129859727efb4326 F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337 F src/printf.c af06f66927919730f03479fed6ae9854f73419f4 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece @@ -227,7 +227,7 @@ F src/shell.c 191129c3f7a9cf241aea90ff6a6be3e74d3767f0 F src/sqlite.h.in 9bbc5815c73b0e77e68b5275481a5e3e7814a804 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 068e42f41a09ce6b9edbe194ac8a470ab53145df +F src/sqliteInt.h 3b17ba74eec22781f51e7b3e4c73d2cbd458f89b F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -296,7 +296,7 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45 -F src/where.c 4dfcd80380d154be434c4b51e890e17ce9754b3e +F src/where.c a7d0434de56d6a4b60cc98ec661969d521201d39 F src/whereInt.h 929c1349b5355fd44f22cee5c14d72b3329c58a6 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1185,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 1e5489faff093d6a8e538061e45532f9050e9459 -R cbfd634bf9c7df43faab424574b6f5df +P 1361450a9dfe9476e8df98f370a3695752252245 +R 114928731acdabb64615a67d8eb69386 U drh -Z a5f816e75181f7c6a373a521ba2c396b +Z 0cd7191a5ffc11f0c0a8249763204863 diff --git a/manifest.uuid b/manifest.uuid index 13453542e7..0455b18c12 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1361450a9dfe9476e8df98f370a3695752252245 \ No newline at end of file +e75b26ee357bb3d3c1a539b05d633ebf314726d7 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 43aff141b2..f9c03dc848 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -1129,7 +1129,7 @@ static void analyzeOneTable( */ sqlite3VdbeAddOp0(v, OP_Goto); addrNextRow = sqlite3VdbeCurrentAddr(v); - if( nColTest==1 && pIdx->nKeyCol==1 && pIdx->onError!=OE_None ){ + if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){ /* For a single-column UNIQUE index, once we have found a non-NULL ** row, we know that all the rest will be distinct, so skip ** subsequent distinctness tests. */ diff --git a/src/build.c b/src/build.c index 384802c533..28205c4c61 100644 --- a/src/build.c +++ b/src/build.c @@ -2707,7 +2707,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); assert( pKey!=0 || db->mallocFailed || pParse->nErr ); - if( pIndex->onError!=OE_None && pKey!=0 ){ + if( IsUniqueIndex(pIndex) && pKey!=0 ){ int j2 = sqlite3VdbeCurrentAddr(v) + 3; sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); addr2 = sqlite3VdbeCurrentAddr(v); @@ -3104,9 +3104,9 @@ Index *sqlite3CreateIndex( Index *pIdx; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int k; - assert( pIdx->onError!=OE_None ); + assert( IsUniqueIndex(pIdx) ); assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF ); - assert( pIndex->onError!=OE_None ); + assert( IsUniqueIndex(pIndex) ); if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue; for(k=0; knKeyCol; k++){ @@ -3297,7 +3297,7 @@ void sqlite3DefaultRowEst(Index *pIdx){ } assert( 0==sqlite3LogEst(1) ); - if( pIdx->onError!=OE_None ) a[pIdx->nKeyCol] = 0; + if( IsUniqueIndex(pIdx) ) a[pIdx->nKeyCol] = 0; } /* diff --git a/src/expr.c b/src/expr.c index aa55ff7af2..3b254f3d3e 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1604,7 +1604,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){ if( (pIdx->aiColumn[0]==iCol) && sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq - && (!mustBeUnique || (pIdx->nKeyCol==1 && pIdx->onError!=OE_None)) + && (!mustBeUnique || (pIdx->nKeyCol==1 && IsUniqueIndex(pIdx))) ){ int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); diff --git a/src/fkey.c b/src/fkey.c index c3cac276a9..50c10da822 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -225,7 +225,7 @@ int sqlite3FkLocateIndex( } for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->nKeyCol==nCol && pIdx->onError!=OE_None ){ + if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){ /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number ** of columns. If each indexed column corresponds to a foreign key ** column of pFKey, then this index is a winner. */ diff --git a/src/insert.c b/src/insert.c index 7b427d1eb6..5964b91ca4 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1886,7 +1886,7 @@ static int xferOptimization( } } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ - if( pDestIdx->onError!=OE_None ){ + if( IsUniqueIndex(pDestIdx) ){ destHasUniqueIdx = 1; } for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){ diff --git a/src/pragma.c b/src/pragma.c index c4374cc71c..a4a1b2a250 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1544,7 +1544,7 @@ void sqlite3Pragma( for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); - sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3); + sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3); } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 5d72295d66..1aede95c14 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1720,6 +1720,9 @@ struct Index { /* Return true if index X is a PRIMARY KEY index */ #define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) +/* Return true if index X is a UNIQUE index */ +#define IsUniqueIndex(X) ((X)->onError!=OE_None) + /* ** Each sample stored in the sqlite_stat3 table is represented in memory ** using a structure of this type. See documentation at the top of the diff --git a/src/where.c b/src/where.c index 38d1014ac0..3cc66a34b1 100644 --- a/src/where.c +++ b/src/where.c @@ -1470,7 +1470,7 @@ static int isDistinctRedundant( ** contain a "col=X" term are subject to a NOT NULL constraint. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - if( pIdx->onError==OE_None ) continue; + if( !IsUniqueIndex(pIdx) ) continue; for(i=0; inKeyCol; i++){ i16 iCol = pIdx->aiColumn[i]; if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){ @@ -4376,7 +4376,7 @@ static int whereLoopAddBtreeIndex( }else if( eOp & (WO_EQ) ){ pNew->wsFlags |= WHERE_COLUMN_EQ; if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){ - if( iCol>=0 && pProbe->onError==OE_None ){ + if( iCol>=0 && !IsUniqueIndex(pProbe) ){ pNew->wsFlags |= WHERE_UNQ_WANTED; }else{ pNew->wsFlags |= WHERE_ONEROW; @@ -5231,7 +5231,7 @@ static i8 wherePathSatisfiesOrderBy( nColumn = pIndex->nColumn; assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); assert( pIndex->aiColumn[nColumn-1]==(-1) || !HasRowid(pIndex->pTable)); - isOrderDistinct = pIndex->onError!=OE_None; + isOrderDistinct = IsUniqueIndex(pIndex); } /* Loop through all columns of the index and deal with the ones @@ -5746,7 +5746,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ assert( pLoop->aLTermSpace==pLoop->aLTerm ); assert( ArraySize(pLoop->aLTermSpace)==4 ); - if( pIdx->onError==OE_None + if( !IsUniqueIndex(pIdx) || pIdx->pPartIdxWhere!=0 || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) ) continue; From cefc87fca5bbfd6bd8f918373de15efd9fe5b413 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 1 Aug 2014 01:40:33 +0000 Subject: [PATCH 10/25] Enhance the PRAGMA integrity_check command to detect UNIQUE and NOT NULL constraint violations. FossilOrigin-Name: 9abcf2698c09f4f6a44a68e74f9f6b538f3253d6 --- manifest | 16 ++++++------- manifest.uuid | 2 +- src/pragma.c | 60 +++++++++++++++++++++++++++++++++++++++++++----- src/vdbe.c | 10 ++++---- test/pragma.test | 27 +++++++++++++++++++++- 5 files changed, 94 insertions(+), 21 deletions(-) diff --git a/manifest b/manifest index 7cd7515a7e..f13081bfc1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Refactoring:\s\sChange\s"pIndex->onError!=OE_None"\sto\suse\sa\smacro:\n"IsUniqueIndex(pIndex)".\s\sEasier\sto\sunderstand\sthat\sway. -D 2014-07-31T22:59:04.121 +C Enhance\sthe\sPRAGMA\sintegrity_check\scommand\sto\sdetect\sUNIQUE\sand\sNOT\sNULL\nconstraint\sviolations. +D 2014-08-01T01:40:33.869 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -216,7 +216,7 @@ F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0 F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c -F src/pragma.c f9268bd5fa072afb3a174149129859727efb4326 +F src/pragma.c d4a33151f057e35e5a2024adf8e41d2817b5c105 F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337 F src/printf.c af06f66927919730f03479fed6ae9854f73419f4 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece @@ -283,7 +283,7 @@ F src/update.c 01564b3c430f6c7b0a35afaf7aba7987206fa3a5 F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05 F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c f87f77b0049cbef1fa68b331c3551d82b4d9fba4 +F src/vdbe.c 115e08834b883964d9a480f685d8601826c5792a F src/vdbe.h c63fad052c9e7388d551e556e119c0bcf6bebdf8 F src/vdbeInt.h f5513f2b5ac1e2c5128996c7ea23add256a301df F src/vdbeapi.c 24e40422382beb774daab11fe9fe9d37e8a04949 @@ -754,7 +754,7 @@ F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54 F test/permutations.test bc474bafb022cc5014ef3a9c3d5ab61d6d6f587c -F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0 +F test/pragma.test 19d0241a007bcdd77fc2606ec60fc60357e7fc8b F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1 @@ -1185,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 1361450a9dfe9476e8df98f370a3695752252245 -R 114928731acdabb64615a67d8eb69386 +P e75b26ee357bb3d3c1a539b05d633ebf314726d7 +R 50d518176c08d9fef67243df4085599b U drh -Z 0cd7191a5ffc11f0c0a8249763204863 +Z ae546b77e53655a859301e9ce422b440 diff --git a/manifest.uuid b/manifest.uuid index 0455b18c12..087d6ad801 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e75b26ee357bb3d3c1a539b05d633ebf314726d7 \ No newline at end of file +9abcf2698c09f4f6a44a68e74f9f6b538f3253d6 \ No newline at end of file diff --git a/src/pragma.c b/src/pragma.c index a4a1b2a250..b37499f7bd 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1908,28 +1908,76 @@ void sqlite3Pragma( pParse->nMem = MAX(pParse->nMem, 8+j); sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); + /* Verify that all NOT NULL columns really are NOT NULL */ + for(j=0; jnCol; j++){ + char *zErr; + int jmp2, jmp3; + if( j==pTab->iPKey ) continue; + if( pTab->aCol[j].notNull==0 ) continue; + sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ + zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, + pTab->aCol[j].zName); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); + sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); + jmp3 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); + sqlite3VdbeAddOp0(v, OP_Halt); + sqlite3VdbeJumpHere(v, jmp2); + sqlite3VdbeJumpHere(v, jmp3); + } + /* Validate index entries for the current row */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ - int jmp2, jmp3, jmp4; + int jmp2, jmp3, jmp4, jmp5; + int ckUniq = sqlite3VdbeMakeLabel(v); if( pPk==pIdx ) continue; r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, pPrior, r1); pPrior = pIdx; sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */ - jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, 0, r1, + /* Verify that an index entry exists for the current table row */ + jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, pIdx->nColumn); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC); sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); - sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, " missing from index ", - P4_STATIC); + sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, + " missing from index ", P4_STATIC); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); - sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pIdx->zName, P4_TRANSIENT); + jmp5 = sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, + pIdx->zName, P4_TRANSIENT); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); sqlite3VdbeAddOp0(v, OP_Halt); - sqlite3VdbeJumpHere(v, jmp4); sqlite3VdbeJumpHere(v, jmp2); + /* For UNIQUE indexes, verify that only one entry exists with the + ** current key. The entry is unique if (1) any column is NULL + ** or (2) the next entry has a different key */ + if( IsUniqueIndex(pIdx) ){ + int uniqOk = sqlite3VdbeMakeLabel(v); + int jmp6; + int kk; + for(kk=0; kknKeyCol; kk++){ + int iCol = pIdx->aiColumn[kk]; + assert( iCol>=0 && iColnCol ); + if( pTab->aCol[iCol].notNull ) continue; + sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk); + VdbeCoverage(v); + } + jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, uniqOk); + sqlite3VdbeJumpHere(v, jmp6); + sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1, + pIdx->nKeyCol); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, + "non-unique entry in index ", P4_STATIC); + sqlite3VdbeAddOp2(v, OP_Goto, 0, jmp5); + sqlite3VdbeResolveLabel(v, uniqOk); + } + sqlite3VdbeJumpHere(v, jmp4); sqlite3ResolvePartIdxLabel(pParse, jmp3); } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); diff --git a/src/vdbe.c b/src/vdbe.c index 52f0f3aa74..07514951a4 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -3747,9 +3747,9 @@ case OP_Seek: { /* in2 */ ** is a prefix of any entry in P1 then a jump is made to P2 and ** P1 is left pointing at the matching entry. ** -** This operation leaves the cursor in a state where it cannot be -** advanced in either direction. In other words, the Next and Prev -** opcodes do not work after this operation. +** This operation leaves the cursor in a state where it can be +** advanced in the forward direction. The Next instruction will work, +** but not the Prev instruction. ** ** See also: NotFound, NoConflict, NotExists. SeekGe */ @@ -3816,7 +3816,7 @@ case OP_Found: { /* jump, in3 */ pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG - pC->seekOp = 0; + pC->seekOp = pOp->opcode; #endif pIn3 = &aMem[pOp->p3]; assert( pC->pCursor!=0 ); @@ -4673,7 +4673,7 @@ case OP_Next: /* jump */ ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */ assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE - || pC->seekOp==OP_Rewind ); + || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found); assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE || pC->seekOp==OP_Last ); diff --git a/test/pragma.test b/test/pragma.test index 8f54e695d7..539d867366 100644 --- a/test/pragma.test +++ b/test/pragma.test @@ -431,7 +431,32 @@ Page 6 is never used} {row 1 missing from index i2}} db eval {PRAGMA integrity_check} } {ok} } -#exit + +# Verify that PRAGMA integrity_check catches UNIQUE and NOT NULL +# constraint violations. +# +do_execsql_test pragma-3.20 { + CREATE TABLE t1(a,b); + CREATE INDEX t1a ON t1(a); + INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(2,4),(NULL,5),(NULL,6); + PRAGMA writable_schema=ON; + UPDATE sqlite_master SET sql='CREATE UNIQUE INDEX t1a ON t1(a)' + WHERE name='t1a'; + UPDATE sqlite_master SET sql='CREATE TABLE t1(a NOT NULL,b)' + WHERE name='t1'; + PRAGMA writable_schema=OFF; + ALTER TABLE t1 RENAME TO t1x; + PRAGMA integrity_check; +} {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a} {NULL value in t1x.a}} +do_execsql_test pragma-3.21 { + PRAGMA integrity_check(3); +} {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a}} +do_execsql_test pragma-3.22 { + PRAGMA integrity_check(2); +} {{non-unique entry in index t1a} {NULL value in t1x.a}} +do_execsql_test pragma-3.21 { + PRAGMA integrity_check(1); +} {{non-unique entry in index t1a}} # Test modifying the cache_size of an attached database. ifcapable pager_pragmas&&attach { From 3a85625d87c2b5d0f4cd504cb4fdc5d8fc5ee8c4 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 1 Aug 2014 14:46:57 +0000 Subject: [PATCH 11/25] Begin making changes to the IN operator in an attempt to make it run faster and to make the code easier to understand. FossilOrigin-Name: ee0fd6aaf94cda1dce3fe752bfe3b0f83e0043f1 --- manifest | 19 ++++++++------- manifest.uuid | 2 +- src/expr.c | 64 +++++++++++++++++++++++++++++-------------------- src/sqliteInt.h | 20 ++++++++++++---- src/where.c | 2 +- 5 files changed, 66 insertions(+), 41 deletions(-) diff --git a/manifest b/manifest index f13081bfc1..3fae6c98bd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\sPRAGMA\sintegrity_check\scommand\sto\sdetect\sUNIQUE\sand\sNOT\sNULL\nconstraint\sviolations. -D 2014-08-01T01:40:33.869 +C Begin\smaking\schanges\sto\sthe\sIN\soperator\sin\san\sattempt\sto\smake\sit\srun\sfaster\nand\sto\smake\sthe\scode\seasier\sto\sunderstand. +D 2014-08-01T14:46:57.155 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 3be0e9f90bb1c475a99a821a11eecde53ecefc1d +F src/expr.c 7c52ea8b322992a91a241c0092a5bf97b141d353 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -227,7 +227,7 @@ F src/shell.c 191129c3f7a9cf241aea90ff6a6be3e74d3767f0 F src/sqlite.h.in 9bbc5815c73b0e77e68b5275481a5e3e7814a804 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 3b17ba74eec22781f51e7b3e4c73d2cbd458f89b +F src/sqliteInt.h 17ece600d3c9d36cc0ee2b74a30507507f3e0937 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -296,7 +296,7 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45 -F src/where.c a7d0434de56d6a4b60cc98ec661969d521201d39 +F src/where.c ce1b9a3a2573033cd15e0882719db7f211f21cdd F src/whereInt.h 929c1349b5355fd44f22cee5c14d72b3329c58a6 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1185,7 +1185,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 e75b26ee357bb3d3c1a539b05d633ebf314726d7 -R 50d518176c08d9fef67243df4085599b +P 9abcf2698c09f4f6a44a68e74f9f6b538f3253d6 +R 1cc42777f2b661f6d0caf162eadc6d85 +T *branch * IN-operator-improvements +T *sym-IN-operator-improvements * +T -sym-trunk * U drh -Z ae546b77e53655a859301e9ce422b440 +Z 08adfdc6013d75458685b1e962a583ca diff --git a/manifest.uuid b/manifest.uuid index 087d6ad801..1b3e9a1eeb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9abcf2698c09f4f6a44a68e74f9f6b538f3253d6 \ No newline at end of file +ee0fd6aaf94cda1dce3fe752bfe3b0f83e0043f1 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 3b254f3d3e..dd7b7c3de1 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1484,7 +1484,7 @@ int sqlite3CodeOnce(Parse *pParse){ ** be used either to test for membership in the RHS set or to iterate through ** all members of the RHS set, skipping duplicates. ** -** A cursor is opened on the b-tree object that the RHS of the IN operator +** A cursor is opened on the b-tree object that is the RHS of the IN operator ** and pX->iTable is set to the index of that cursor. ** ** The returned value of this function indicates the b-tree type, as follows: @@ -1494,6 +1494,8 @@ int sqlite3CodeOnce(Parse *pParse){ ** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index. ** IN_INDEX_EPH - The cursor was opened on a specially created and ** populated epheremal table. +** IN_INDEX_NOOP - No cursor was allocated. The in operator must be +** implemented as a sequence of comparisons. ** ** An existing b-tree might be used if the RHS expression pX is a simple ** subquery such as: @@ -1503,23 +1505,37 @@ int sqlite3CodeOnce(Parse *pParse){ ** If the RHS of the IN operator is a list or a more complex subquery, then ** an ephemeral table might need to be generated from the RHS and then ** pX->iTable made to point to the ephermeral table instead of an -** existing table. +** existing table. ** -** If the prNotFound parameter is 0, then the b-tree will be used to iterate -** through the set members, skipping any duplicates. In this case an -** epheremal table must be used unless the selected is guaranteed +** The inFlags parameter must contain exactly one of the bits +** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP. If inFlags contains +** IN_INDEX_MEMBERSHIP, then the generated table will be used for a +** fast membership test. When the IN_INDEX_LOOP bit is set, the +** IN index will be used to loop over all values of the RHS of the +** IN operator. +** +** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate +** through the set members) then the b-tree must not contain duplicates. +** An epheremal table must be used unless the selected is guaranteed ** to be unique - either because it is an INTEGER PRIMARY KEY or it ** has a UNIQUE constraint or UNIQUE index. ** -** If the prNotFound parameter is not 0, then the b-tree will be used -** for fast set membership tests. In this case an epheremal table must +** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used +** for fast set membership tests) then an epheremal table must ** be used unless is an INTEGER PRIMARY KEY or an index can ** be found with as its left-most column. ** +** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and +** if the RHS of the IN operator is a list (not a subquery) then this +** routine might decide that creating an ephemeral b-tree for membership +** testing is too expensive and return IN_INDEX_NOOP. IN that case, the +** calling routine should implement the IN operator using a sequence +** of Eq or Ne comparison operations. +** ** When the b-tree is being used for membership tests, the calling function -** needs to know whether or not the structure contains an SQL NULL -** value in order to correctly evaluate expressions like "X IN (Y, Z)". -** If there is any chance that the (...) might contain a NULL value at +** might need to know whether or not the RHS side of the IN operator +** contains a NULL. If prNotFound is not NULL and +** if there is any chance that the (...) might contain a NULL value at ** runtime, then a register is allocated and the register number written ** to *prNotFound. If there is no chance that the (...) contains a ** NULL value, then *prNotFound is left unchanged. @@ -1540,14 +1556,15 @@ int sqlite3CodeOnce(Parse *pParse){ ** test more often than is necessary. */ #ifndef SQLITE_OMIT_SUBQUERY -int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ +int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prNotFound){ Select *p; /* SELECT to the right of IN operator */ int eType = 0; /* Type of RHS table. IN_INDEX_* */ int iTab = pParse->nTab++; /* Cursor of the RHS table */ - int mustBeUnique = (prNotFound==0); /* True if RHS must be unique */ + int mustBeUnique; /* True if RHS must be unique */ Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */ assert( pX->op==TK_IN ); + mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0; /* Check to see if an existing table or index can be used to ** satisfy the query. This is preferable to generating a new @@ -1630,14 +1647,14 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ u32 savedNQueryLoop = pParse->nQueryLoop; int rMayHaveNull = 0; eType = IN_INDEX_EPH; - if( prNotFound ){ - *prNotFound = rMayHaveNull = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); - }else{ + if( inFlags & IN_INDEX_LOOP ){ pParse->nQueryLoop = 0; if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ eType = IN_INDEX_ROWID; } + }else if( prNotFound ){ + *prNotFound = rMayHaveNull = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull); } sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID); pParse->nQueryLoop = savedNQueryLoop; @@ -1668,15 +1685,9 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ ** ** If rMayHaveNull is non-zero, that means that the operation is an IN ** (not a SELECT or EXISTS) and that the RHS might contains NULLs. -** Furthermore, the IN is in a WHERE clause and that we really want -** to iterate over the RHS of the IN operator in order to quickly locate -** all corresponding LHS elements. All this routine does is initialize -** the register given by rMayHaveNull to NULL. Calling routines will take -** care of changing this register value to non-NULL if the RHS is NULL-free. -** -** If rMayHaveNull is zero, that means that the subquery is being used -** for membership testing only. There is no need to initialize any -** registers to indicate the presence or absence of NULLs on the RHS. +** All this routine does is initialize the register given by rMayHaveNull +** to NULL. Calling routines will take care of changing this register +** value to non-NULL if the RHS is NULL-free. ** ** For a SELECT or EXISTS operator, return the register that holds the ** result. For IN operators or if an error occurs, the return value is 0. @@ -1928,7 +1939,8 @@ static void sqlite3ExprCodeIN( v = pParse->pVdbe; assert( v!=0 ); /* OOM detected prior to this routine */ VdbeNoopComment((v, "begin IN expr")); - eType = sqlite3FindInIndex(pParse, pExpr, &rRhsHasNull); + eType = sqlite3FindInIndex(pParse, pExpr, 0, + destIfFalse==destIfNull ? 0 : &rRhsHasNull); /* Figure out the affinity to use to create a key from the results ** of the expression. affinityStr stores a static string suitable for diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 1aede95c14..784fd0fd93 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3591,11 +3591,21 @@ const char *sqlite3JournalModename(int); #define sqlite3EndBenignMalloc() #endif -#define IN_INDEX_ROWID 1 -#define IN_INDEX_EPH 2 -#define IN_INDEX_INDEX_ASC 3 -#define IN_INDEX_INDEX_DESC 4 -int sqlite3FindInIndex(Parse *, Expr *, int*); +/* +** Allowed return values from sqlite3FindInIndex() +*/ +#define IN_INDEX_ROWID 1 /* Search the rowid of the table */ +#define IN_INDEX_EPH 2 /* Search an ephemeral b-tree */ +#define IN_INDEX_INDEX_ASC 3 /* Existing index ASCENDING */ +#define IN_INDEX_INDEX_DESC 4 /* Existing index DESCENDING */ +#define IN_INDEX_NOOP 5 /* No table available. Use comparisons */ +/* +** Allowed flags for the 3rd parameter to sqlite3FindInIndex(). +*/ +#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ +#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ +#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ +int sqlite3FindInIndex(Parse *, Expr *, u32, int*); #ifdef SQLITE_ENABLE_ATOMIC_WRITE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); diff --git a/src/where.c b/src/where.c index 3cc66a34b1..20823046f7 100644 --- a/src/where.c +++ b/src/where.c @@ -2522,7 +2522,7 @@ static int codeEqualityTerm( } assert( pX->op==TK_IN ); iReg = iTarget; - eType = sqlite3FindInIndex(pParse, pX, 0); + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0); if( eType==IN_INDEX_INDEX_DESC ){ testcase( bRev ); bRev = !bRev; From e80c9b9ad5e62af9ccd8a4ce8f069c965dde6070 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 1 Aug 2014 15:34:36 +0000 Subject: [PATCH 12/25] The idea of coding IN operator with a short list on the RHS as an OR expression turns out to be helpful. If the list is of length 1 or 2, the OR expression is very slightly faster, but the ephemeral table approach is clearly better for all list lengths greater than 2. Better to keep the code simple. FossilOrigin-Name: e13175d3579e1045165bab091b3b28951d691704 --- manifest | 17 +++++++---------- manifest.uuid | 2 +- src/expr.c | 14 +++----------- src/sqliteInt.h | 6 ++---- 4 files changed, 13 insertions(+), 26 deletions(-) diff --git a/manifest b/manifest index 3fae6c98bd..76ab0745e9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Begin\smaking\schanges\sto\sthe\sIN\soperator\sin\san\sattempt\sto\smake\sit\srun\sfaster\nand\sto\smake\sthe\scode\seasier\sto\sunderstand. -D 2014-08-01T14:46:57.155 +C The\sidea\sof\scoding\sIN\soperator\swith\sa\sshort\slist\son\sthe\sRHS\sas\san\sOR\sexpression\nturns\sout\sto\sbe\shelpful.\s\sIf\sthe\slist\sis\sof\slength\s1\sor\s2,\sthe\sOR\sexpression\nis\svery\sslightly\sfaster,\sbut\sthe\sephemeral\stable\sapproach\sis\sclearly\sbetter\sfor\nall\slist\slengths\sgreater\sthan\s2.\s\sBetter\sto\skeep\sthe\scode\ssimple. +D 2014-08-01T15:34:36.551 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 7c52ea8b322992a91a241c0092a5bf97b141d353 +F src/expr.c 1f7fa7ddbdffd89898a3ce5ff1e57d137ec87aa5 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -227,7 +227,7 @@ F src/shell.c 191129c3f7a9cf241aea90ff6a6be3e74d3767f0 F src/sqlite.h.in 9bbc5815c73b0e77e68b5275481a5e3e7814a804 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 17ece600d3c9d36cc0ee2b74a30507507f3e0937 +F src/sqliteInt.h 5cee19f34f6efe6e6f7733d55a5c59e3a35a378a F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -1185,10 +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 9abcf2698c09f4f6a44a68e74f9f6b538f3253d6 -R 1cc42777f2b661f6d0caf162eadc6d85 -T *branch * IN-operator-improvements -T *sym-IN-operator-improvements * -T -sym-trunk * +P ee0fd6aaf94cda1dce3fe752bfe3b0f83e0043f1 +R b49330a02feffafe84f051ae1dbb9076 U drh -Z 08adfdc6013d75458685b1e962a583ca +Z f695386e744e4159654587b52ac0d789 diff --git a/manifest.uuid b/manifest.uuid index 1b3e9a1eeb..9b33d2f23a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ee0fd6aaf94cda1dce3fe752bfe3b0f83e0043f1 \ No newline at end of file +e13175d3579e1045165bab091b3b28951d691704 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index dd7b7c3de1..d818827107 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1494,8 +1494,6 @@ int sqlite3CodeOnce(Parse *pParse){ ** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index. ** IN_INDEX_EPH - The cursor was opened on a specially created and ** populated epheremal table. -** IN_INDEX_NOOP - No cursor was allocated. The in operator must be -** implemented as a sequence of comparisons. ** ** An existing b-tree might be used if the RHS expression pX is a simple ** subquery such as: @@ -1525,13 +1523,6 @@ int sqlite3CodeOnce(Parse *pParse){ ** be used unless is an INTEGER PRIMARY KEY or an index can ** be found with as its left-most column. ** -** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and -** if the RHS of the IN operator is a list (not a subquery) then this -** routine might decide that creating an ephemeral b-tree for membership -** testing is too expensive and return IN_INDEX_NOOP. IN that case, the -** calling routine should implement the IN operator using a sequence -** of Eq or Ne comparison operations. -** ** When the b-tree is being used for membership tests, the calling function ** might need to know whether or not the RHS side of the IN operator ** contains a NULL. If prNotFound is not NULL and @@ -1939,7 +1930,7 @@ static void sqlite3ExprCodeIN( v = pParse->pVdbe; assert( v!=0 ); /* OOM detected prior to this routine */ VdbeNoopComment((v, "begin IN expr")); - eType = sqlite3FindInIndex(pParse, pExpr, 0, + eType = sqlite3FindInIndex(pParse, pExpr, IN_INDEX_MEMBERSHIP, destIfFalse==destIfNull ? 0 : &rRhsHasNull); /* Figure out the affinity to use to create a key from the results @@ -1986,7 +1977,8 @@ static void sqlite3ExprCodeIN( ** contains one or more NULL values, then the result of the ** expression is also NULL. */ - if( rRhsHasNull==0 || destIfFalse==destIfNull ){ + assert( destIfFalse!=destIfNull || rRhsHasNull==0 ); + if( rRhsHasNull==0 ){ /* This branch runs if it is known at compile time that the RHS ** cannot contain NULL values. This happens as the result ** of a "NOT NULL" constraint in the database schema. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 784fd0fd93..97fb2d46e4 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3598,13 +3598,11 @@ const char *sqlite3JournalModename(int); #define IN_INDEX_EPH 2 /* Search an ephemeral b-tree */ #define IN_INDEX_INDEX_ASC 3 /* Existing index ASCENDING */ #define IN_INDEX_INDEX_DESC 4 /* Existing index DESCENDING */ -#define IN_INDEX_NOOP 5 /* No table available. Use comparisons */ /* ** Allowed flags for the 3rd parameter to sqlite3FindInIndex(). */ -#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ -#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ -#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ +#define IN_INDEX_MEMBERSHIP 0x0001 /* IN operator used for membership test */ +#define IN_INDEX_LOOP 0x0002 /* IN operator used as a loop */ int sqlite3FindInIndex(Parse *, Expr *, u32, int*); #ifdef SQLITE_ENABLE_ATOMIC_WRITE From e21a6e1dfe2196184bf17e9d9212f3eae0b346e5 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 1 Aug 2014 18:00:24 +0000 Subject: [PATCH 13/25] Remove an unnecessary OP_Null in the IN-operator logic. Attempt to clarify comments explaining the IN-operator code, though it is not clear that the comments are correct even yet - more work to be done. FossilOrigin-Name: c11e55fabbc718cb324ecd3540453c25db98f50c --- manifest | 15 +++++++-------- manifest.uuid | 2 +- src/expr.c | 42 +++++++++++++++++++++++------------------- src/vdbe.c | 4 ++-- 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/manifest b/manifest index d534cb249b..2762bc4675 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Clean\sup\sthe\sIN\soperator\scode\sgeneration\slogic\sto\smake\sit\seasier\sto\sreason\nabout.\s\sIn\sthe\sprocess,\simprove\scode\sgeneration\sto\somit\ssome\sunused\sOP_Null\noperations. -D 2014-08-01T15:51:36.528 +C Remove\san\sunnecessary\sOP_Null\sin\sthe\sIN-operator\slogic.\s\sAttempt\sto\sclarify\ncomments\sexplaining\sthe\sIN-operator\scode,\sthough\sit\sis\snot\sclear\sthat\sthe\ncomments\sare\scorrect\seven\syet\s-\smore\swork\sto\sbe\sdone. +D 2014-08-01T18:00:24.770 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 1f7fa7ddbdffd89898a3ce5ff1e57d137ec87aa5 +F src/expr.c 45da7f2dd6b5c52b3210387956711d578bdceb37 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -283,7 +283,7 @@ F src/update.c 01564b3c430f6c7b0a35afaf7aba7987206fa3a5 F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05 F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c 115e08834b883964d9a480f685d8601826c5792a +F src/vdbe.c b9e6866e43a61ca4080410f27c4bb52823495186 F src/vdbe.h c63fad052c9e7388d551e556e119c0bcf6bebdf8 F src/vdbeInt.h f5513f2b5ac1e2c5128996c7ea23add256a301df F src/vdbeapi.c 24e40422382beb774daab11fe9fe9d37e8a04949 @@ -1185,8 +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 9abcf2698c09f4f6a44a68e74f9f6b538f3253d6 e13175d3579e1045165bab091b3b28951d691704 -R b49330a02feffafe84f051ae1dbb9076 -T +closed e13175d3579e1045165bab091b3b28951d691704 +P 7c6fbcfe6ed5739e8e4639b7b123fbf9828cbfc0 +R 76f22de612006799aae8055deaa164fe U drh -Z e21436d3fd2e7daacda65f50d724cf15 +Z ebc1ba4c7f530e221b3bc2fcb7e1119a diff --git a/manifest.uuid b/manifest.uuid index 06cf7d6673..ef13592241 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7c6fbcfe6ed5739e8e4639b7b123fbf9828cbfc0 \ No newline at end of file +c11e55fabbc718cb324ecd3540453c25db98f50c \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index d818827107..591ea9845c 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1525,29 +1525,34 @@ int sqlite3CodeOnce(Parse *pParse){ ** ** When the b-tree is being used for membership tests, the calling function ** might need to know whether or not the RHS side of the IN operator -** contains a NULL. If prNotFound is not NULL and +** contains a NULL. If prRhsHasNull is not a NULL pointer and ** if there is any chance that the (...) might contain a NULL value at ** runtime, then a register is allocated and the register number written -** to *prNotFound. If there is no chance that the (...) contains a -** NULL value, then *prNotFound is left unchanged. +** to *prRhsHasNull. If there is no chance that the (...) contains a +** NULL value, then *prRhsHasNull is left unchanged. ** -** If a register is allocated and its location stored in *prNotFound, then -** its initial value is NULL. If the (...) does not remain constant -** for the duration of the query (i.e. the SELECT within the (...) -** is a correlated subquery) then the value of the allocated register is -** reset to NULL each time the subquery is rerun. This allows the -** caller to use vdbe code equivalent to the following: +** If a register is allocated and its location stored in *prRhsHasNull, then +** the value in that register will be: ** -** if( register==NULL ){ -** has_null = -** register = 1 +** 0 if the (...) contains no NULL values +** 1 if the (...) does not contain NULL values +** NULL if we do not yet know if (...) contains NULLs +** +** If the (...) does not remain constant for the duration of the query +** (i.e. the SELECT within the (...) is a correlated subquery) then the +** value of the allocated register is reset to NULL each time the subquery +** is rerun. This allows the caller to use vdbe code equivalent to the +** following: +** +** if( r[*prRhsHasNull] IS NULL ){ +** r[*prRhsHasNull] = ** } ** ** in order to avoid running the ** test more often than is necessary. */ #ifndef SQLITE_OMIT_SUBQUERY -int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prNotFound){ +int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){ Select *p; /* SELECT to the right of IN operator */ int eType = 0; /* Type of RHS table. IN_INDEX_* */ int iTab = pParse->nTab++; /* Cursor of the RHS table */ @@ -1621,9 +1626,9 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prNotFound){ assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; - if( prNotFound && !pTab->aCol[iCol].notNull ){ - *prNotFound = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); + if( prRhsHasNull && !pTab->aCol[iCol].notNull ){ + *prRhsHasNull = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Null, 0, *prRhsHasNull); } sqlite3VdbeJumpHere(v, iAddr); } @@ -1643,9 +1648,8 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prNotFound){ if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ eType = IN_INDEX_ROWID; } - }else if( prNotFound ){ - *prNotFound = rMayHaveNull = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull); + }else if( prRhsHasNull ){ + *prRhsHasNull = rMayHaveNull = ++pParse->nMem; } sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID); pParse->nQueryLoop = savedNQueryLoop; diff --git a/src/vdbe.c b/src/vdbe.c index 07514951a4..ade82b054a 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2229,13 +2229,13 @@ case OP_Once: { /* jump */ ** ** Jump to P2 if the value in register P1 is true. The value ** is considered true if it is numeric and non-zero. If the value -** in P1 is NULL then take the jump if P3 is non-zero. +** in P1 is NULL then take the jump if and only if P3 is non-zero. */ /* Opcode: IfNot P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is False. The value ** is considered false if it has a numeric value of zero. If the value -** in P1 is NULL then take the jump if P3 is zero. +** in P1 is NULL then take the jump if and only if P3 is non-zero. */ case OP_If: /* jump, in1 */ case OP_IfNot: { /* jump, in1 */ From 6be515ebe0c6976352efd82cd6cddebe4b43361f Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 1 Aug 2014 21:00:53 +0000 Subject: [PATCH 14/25] Improved detection and handling of NULL values on the RHS of a IN operator. FossilOrigin-Name: 468e730036edac22cfeb9ea3515aa16e6bcd6650 --- manifest | 12 +++---- manifest.uuid | 2 +- src/expr.c | 94 ++++++++++++++++++++++----------------------------- 3 files changed, 47 insertions(+), 61 deletions(-) diff --git a/manifest b/manifest index 2762bc4675..5a22fd3d13 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sunnecessary\sOP_Null\sin\sthe\sIN-operator\slogic.\s\sAttempt\sto\sclarify\ncomments\sexplaining\sthe\sIN-operator\scode,\sthough\sit\sis\snot\sclear\sthat\sthe\ncomments\sare\scorrect\seven\syet\s-\smore\swork\sto\sbe\sdone. -D 2014-08-01T18:00:24.770 +C Improved\sdetection\sand\shandling\sof\sNULL\svalues\son\sthe\sRHS\sof\sa\sIN\soperator. +D 2014-08-01T21:00:53.855 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 45da7f2dd6b5c52b3210387956711d578bdceb37 +F src/expr.c ac35f4c83ccc090e4b31bf3c839d519762a86fd5 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -1185,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 7c6fbcfe6ed5739e8e4639b7b123fbf9828cbfc0 -R 76f22de612006799aae8055deaa164fe +P c11e55fabbc718cb324ecd3540453c25db98f50c +R d4c66ce9989f6295fb51f65762a6a30b U drh -Z ebc1ba4c7f530e221b3bc2fcb7e1119a +Z 526f21f790d2042539b4ae116e22530d diff --git a/manifest.uuid b/manifest.uuid index ef13592241..4742ee228e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c11e55fabbc718cb324ecd3540453c25db98f50c \ No newline at end of file +468e730036edac22cfeb9ea3515aa16e6bcd6650 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 591ea9845c..6440dea397 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1475,6 +1475,22 @@ int sqlite3CodeOnce(Parse *pParse){ return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++); } +/* +** Generate code that checks the single-column index table iCur to see if +** contains any NULL entries. Cause the register at regHasNull to be set +** to a non-NULL value if iCur contains no NULLs. Cause register regHasNull +** to be set to NULL if iCur contains one or more NULL values. +*/ +static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ + int j1; + sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull); + j1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + VdbeComment((v, "")); + sqlite3VdbeJumpHere(v, j1); +} + /* ** This function is used by the implementation of the IN (...) operator. ** The pX parameter is the expression on the RHS of the IN operator, which @@ -1532,24 +1548,9 @@ int sqlite3CodeOnce(Parse *pParse){ ** NULL value, then *prRhsHasNull is left unchanged. ** ** If a register is allocated and its location stored in *prRhsHasNull, then -** the value in that register will be: -** -** 0 if the (...) contains no NULL values -** 1 if the (...) does not contain NULL values -** NULL if we do not yet know if (...) contains NULLs -** -** If the (...) does not remain constant for the duration of the query -** (i.e. the SELECT within the (...) is a correlated subquery) then the -** value of the allocated register is reset to NULL each time the subquery -** is rerun. This allows the caller to use vdbe code equivalent to the -** following: -** -** if( r[*prRhsHasNull] IS NULL ){ -** r[*prRhsHasNull] = -** } -** -** in order to avoid running the -** test more often than is necessary. +** the value in that register will be NULL if the b-tree contains one or more +** NULL values, and it will be some non-NULL value if the b-tree contains no +** NULL values. */ #ifndef SQLITE_OMIT_SUBQUERY int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){ @@ -1628,7 +1629,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){ if( prRhsHasNull && !pTab->aCol[iCol].notNull ){ *prRhsHasNull = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Null, 0, *prRhsHasNull); + sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull); } sqlite3VdbeJumpHere(v, iAddr); } @@ -1691,10 +1692,10 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){ int sqlite3CodeSubselect( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The IN, SELECT, or EXISTS operator */ - int rMayHaveNull, /* Register that records whether NULLs exist in RHS */ + int rHasNullFlag, /* Register that records whether NULLs exist in RHS */ int isRowid /* If true, LHS of IN operator is a rowid */ ){ - int testAddr = -1; /* One-time test address */ + int jmpIfDynamic = -1; /* One-time test address */ int rReg = 0; /* Register storing resulting */ Vdbe *v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return 0; @@ -1711,13 +1712,13 @@ int sqlite3CodeSubselect( ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasProperty(pExpr, EP_VarSelect) ){ - testAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); + jmpIfDynamic = sqlite3CodeOnce(pParse); VdbeCoverage(v); } #ifndef SQLITE_OMIT_EXPLAIN if( pParse->explain==2 ){ char *zMsg = sqlite3MPrintf( - pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr>=0?"":"CORRELATED ", + pParse->db, "EXECUTE %s%s SUBQUERY %d", jmpIfDynamic>=0?"":"CORRELATED ", pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId ); sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); @@ -1731,10 +1732,6 @@ int sqlite3CodeSubselect( Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */ KeyInfo *pKeyInfo = 0; /* Key information */ - if( rMayHaveNull ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull); - } - affinity = sqlite3ExprAffinity(pLeft); /* Whether this is an 'x IN(SELECT...)' or an 'x IN()' @@ -1817,9 +1814,9 @@ int sqlite3CodeSubselect( ** this code only executes once. Because for a non-constant ** expression we need to rerun this code each time. */ - if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){ - sqlite3VdbeChangeToNoop(v, testAddr); - testAddr = -1; + if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){ + sqlite3VdbeChangeToNoop(v, jmpIfDynamic); + jmpIfDynamic = -1; } /* Evaluate the expression and insert it into the temp table */ @@ -1889,8 +1886,12 @@ int sqlite3CodeSubselect( } } - if( testAddr>=0 ){ - sqlite3VdbeJumpHere(v, testAddr); + if( rHasNullFlag ){ + sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag); + } + + if( jmpIfDynamic>=0 ){ + sqlite3VdbeJumpHere(v, jmpIfDynamic); } sqlite3ExprCachePop(pParse); @@ -1911,7 +1912,7 @@ int sqlite3CodeSubselect( ** if the LHS is NULL or if the LHS is not contained within the RHS and the ** RHS contains one or more NULL values. ** -** This routine generates code will jump to destIfFalse if the LHS is not +** This routine generates code that jumps to destIfFalse if the LHS is not ** contained within the RHS. If due to NULLs we cannot determine if the LHS ** is contained in the RHS then jump to destIfNull. If the LHS is contained ** within the RHS then fall through. @@ -1997,34 +1998,19 @@ static void sqlite3ExprCodeIN( ** the presence of a NULL on the RHS makes a difference in the ** outcome. */ - int j1, j2; + int j1; /* First check to see if the LHS is contained in the RHS. If so, - ** then the presence of NULLs in the RHS does not matter, so jump - ** over all of the code that follows. + ** then the answer is TRUE the presence of NULLs in the RHS does + ** not matter. If the LHS is not contained in the RHS, then the + ** answer is NULL if the RHS contains NULLs and the answer is + ** FALSE if the RHS is NULL-free. */ j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1); VdbeCoverage(v); - - /* Here we begin generating code that runs if the LHS is not - ** contained within the RHS. Generate additional code that - ** tests the RHS for NULLs. If the RHS contains a NULL then - ** jump to destIfNull. If there are no NULLs in the RHS then - ** jump to destIfFalse. - */ - sqlite3VdbeAddOp2(v, OP_If, rRhsHasNull, destIfNull); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_IfNot, rRhsHasNull, destIfFalse); VdbeCoverage(v); - j2 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, rRhsHasNull, 1); + sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Integer, 0, rRhsHasNull); sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); - sqlite3VdbeJumpHere(v, j2); - sqlite3VdbeAddOp2(v, OP_Integer, 1, rRhsHasNull); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); - - /* The OP_Found at the top of this branch jumps here when true, - ** causing the overall IN expression evaluation to fall through. - */ sqlite3VdbeJumpHere(v, j1); } } From 4c259e9f40a0580c60455f9f4b7492f1d99749a7 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 1 Aug 2014 21:12:35 +0000 Subject: [PATCH 15/25] A better comment on the generated code for the NULL-in-RHS-of-IN detection logic. FossilOrigin-Name: 9bc1c730a366e75b760b58e7a343d39165b2a469 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/expr.c | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 5a22fd3d13..6b5c8679ce 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\sdetection\sand\shandling\sof\sNULL\svalues\son\sthe\sRHS\sof\sa\sIN\soperator. -D 2014-08-01T21:00:53.855 +C A\sbetter\scomment\son\sthe\sgenerated\scode\sfor\sthe\sNULL-in-RHS-of-IN\sdetection\nlogic. +D 2014-08-01T21:12:35.509 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c ac35f4c83ccc090e4b31bf3c839d519762a86fd5 +F src/expr.c 564c28f4f68c30103ba4d8ef60b53f178f60eeb3 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -1185,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 c11e55fabbc718cb324ecd3540453c25db98f50c -R d4c66ce9989f6295fb51f65762a6a30b +P 468e730036edac22cfeb9ea3515aa16e6bcd6650 +R 894229228ea8340c8d39c1accaa43c91 U drh -Z 526f21f790d2042539b4ae116e22530d +Z 2180e0f63fb08551c10fb11eafeeb559 diff --git a/manifest.uuid b/manifest.uuid index 4742ee228e..764209da3f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -468e730036edac22cfeb9ea3515aa16e6bcd6650 \ No newline at end of file +9bc1c730a366e75b760b58e7a343d39165b2a469 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 6440dea397..c32affe34c 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1476,8 +1476,8 @@ int sqlite3CodeOnce(Parse *pParse){ } /* -** Generate code that checks the single-column index table iCur to see if -** contains any NULL entries. Cause the register at regHasNull to be set +** Generate code that checks the left-most column of index table iCur to see if +** it contains any NULL entries. Cause the register at regHasNull to be set ** to a non-NULL value if iCur contains no NULLs. Cause register regHasNull ** to be set to NULL if iCur contains one or more NULL values. */ @@ -1487,7 +1487,7 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ j1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); - VdbeComment((v, "")); + VdbeComment((v, "first_entry_in(%d)", iCur)); sqlite3VdbeJumpHere(v, j1); } From 16d511a664c58b7410ce00fefabcbe8a72e347fe Mon Sep 17 00:00:00 2001 From: mistachkin Date: Sat, 2 Aug 2014 20:44:13 +0000 Subject: [PATCH 16/25] Remove (newly) incorrect preprocessor check to fix build on WinRT. FossilOrigin-Name: ba7826542908eac2e14789d183d0b3e35b143fed --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/os_win.c | 3 +-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 6b5c8679ce..ae65d8580f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C A\sbetter\scomment\son\sthe\sgenerated\scode\sfor\sthe\sNULL-in-RHS-of-IN\sdetection\nlogic. -D 2014-08-01T21:12:35.509 +C Remove\s(newly)\sincorrect\spreprocessor\scheck\sto\sfix\sbuild\son\sWinRT. +D 2014-08-02T20:44:13.563 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -208,7 +208,7 @@ 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 c67bec43e5dadde8029470ab7b7825ccc9abe578 +F src/os_win.c e5f0fc446a682b70db3397d14cca9806d9a15d12 F src/os_win.h 057344a6720b4c8405d9bd98f58cb37a6ee46c25 F src/pager.c f6bb1fa6cdf2062f2d8aec3e64db302bca519ab8 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 @@ -1185,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 468e730036edac22cfeb9ea3515aa16e6bcd6650 -R 894229228ea8340c8d39c1accaa43c91 -U drh -Z 2180e0f63fb08551c10fb11eafeeb559 +P 9bc1c730a366e75b760b58e7a343d39165b2a469 +R 8c9bd54f21254a5c39cdbf67a68f6f01 +U mistachkin +Z a3832f522ef0a90c3ccd915e060c6930 diff --git a/manifest.uuid b/manifest.uuid index 764209da3f..d8a5cdba49 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9bc1c730a366e75b760b58e7a343d39165b2a469 \ No newline at end of file +ba7826542908eac2e14789d183d0b3e35b143fed \ No newline at end of file diff --git a/src/os_win.c b/src/os_win.c index fd2997206c..f770f13862 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -415,8 +415,7 @@ const sqlite3_mem_methods *sqlite3MemGetWin32(void); */ #ifdef SQLITE_TEST LONG volatile sqlite3_os_type = 0; -#elif !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ - defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_HAS_WIDE) +#else static LONG volatile sqlite3_os_type = 0; #endif From bb53ecb1dbd36de81519086bab2c6589640daf49 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 2 Aug 2014 21:03:33 +0000 Subject: [PATCH 17/25] Enhancements to the code generator for the IN operator that result in much faster queries in some cases, for example when the RHS of the IN operator changes for each row of a large table scan. FossilOrigin-Name: 436e884215e2b33ca3fbb555362237b12827c07a --- manifest | 23 +++-- manifest.uuid | 2 +- src/expr.c | 195 ++++++++++++++++++++++++++++----------- src/sqliteInt.h | 6 +- test/in4.test | 4 +- test/tkt-80e031a00f.test | 4 + 6 files changed, 165 insertions(+), 69 deletions(-) diff --git a/manifest b/manifest index ae65d8580f..0a8cdbcd1c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\s(newly)\sincorrect\spreprocessor\scheck\sto\sfix\sbuild\son\sWinRT. -D 2014-08-02T20:44:13.563 +C Enhancements\sto\sthe\scode\sgenerator\sfor\sthe\sIN\soperator\sthat\sresult\sin\smuch\nfaster\squeries\sin\ssome\scases,\sfor\sexample\swhen\sthe\sRHS\sof\sthe\sIN\soperator\nchanges\sfor\seach\srow\sof\sa\slarge\stable\sscan. +D 2014-08-02T21:03:33.699 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 564c28f4f68c30103ba4d8ef60b53f178f60eeb3 +F src/expr.c 89574df1ed8ca967fdd5be0e370722e508b91c2b F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -227,7 +227,7 @@ F src/shell.c 191129c3f7a9cf241aea90ff6a6be3e74d3767f0 F src/sqlite.h.in 9bbc5815c73b0e77e68b5275481a5e3e7814a804 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 5cee19f34f6efe6e6f7733d55a5c59e3a35a378a +F src/sqliteInt.h 17ece600d3c9d36cc0ee2b74a30507507f3e0937 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -607,7 +607,7 @@ F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 -F test/in4.test 41c1c031aa46b1eb4411df2687ed2ed498da23b5 +F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068 F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3 F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328 F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600 @@ -901,7 +901,7 @@ F test/tkt-78e04e52ea.test 813779f8888f3ca226df656c4eef078f9635f3c9 F test/tkt-7a31705a7e6.test e75a2bba4eec801b92c8040eb22096ac6d35e844 F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18 F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8 -F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7 +F test/tkt-80e031a00f.test f50046f474ecf67ad5c50cd9200da04ff887d7cd F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356 F test/tkt-8c63ff0ec.test 258b7fc8d7e4e1cb5362c7d65c143528b9c4cbed @@ -1185,7 +1185,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 9bc1c730a366e75b760b58e7a343d39165b2a469 -R 8c9bd54f21254a5c39cdbf67a68f6f01 -U mistachkin -Z a3832f522ef0a90c3ccd915e060c6930 +P ba7826542908eac2e14789d183d0b3e35b143fed +R 93a5c3d553517a616682ed62728bfb2c +T *branch * IN-operator-improvements +T *sym-IN-operator-improvements * +T -sym-trunk * +U drh +Z c474e62d8861a07a170ddf9e71c3b1a9 diff --git a/manifest.uuid b/manifest.uuid index d8a5cdba49..0ddf2ad117 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ba7826542908eac2e14789d183d0b3e35b143fed \ No newline at end of file +436e884215e2b33ca3fbb555362237b12827c07a \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index c32affe34c..7565d41b90 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1491,6 +1491,24 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ sqlite3VdbeJumpHere(v, j1); } + +#ifndef SQLITE_OMIT_SUBQUERY +/* +** The argument is an IN operator with a list (not a subquery) on the +** right-hand side. Return TRUE if that list is constant. +*/ +static int sqlite3InRhsIsConstant(Expr *pIn){ + Expr *pLHS; + int res; + assert( !ExprHasProperty(pIn, EP_xIsSelect) ); + pLHS = pIn->pLeft; + pIn->pLeft = 0; + res = sqlite3ExprIsConstant(pIn); + pIn->pLeft = pLHS; + return res; +} +#endif + /* ** This function is used by the implementation of the IN (...) operator. ** The pX parameter is the expression on the RHS of the IN operator, which @@ -1510,6 +1528,8 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ ** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index. ** IN_INDEX_EPH - The cursor was opened on a specially created and ** populated epheremal table. +** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be +** implemented as a sequence of comparisons. ** ** An existing b-tree might be used if the RHS expression pX is a simple ** subquery such as: @@ -1539,6 +1559,13 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){ ** be used unless is an INTEGER PRIMARY KEY or an index can ** be found with as its left-most column. ** +** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and +** if the RHS of the IN operator is a list (not a subquery) then this +** routine might decide that creating an ephemeral b-tree for membership +** testing is too expensive and return IN_INDEX_NOOP. In that case, the +** calling routine should implement the IN operator using a sequence +** of Eq or Ne comparison operations. +** ** When the b-tree is being used for membership tests, the calling function ** might need to know whether or not the RHS side of the IN operator ** contains a NULL. If prRhsHasNull is not a NULL pointer and @@ -1637,6 +1664,22 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){ } } + /* If no preexisting index is available for the IN clause + ** and IN_INDEX_NOOP is an allowed reply + ** and the RHS of the IN operator is a list, not a subquery + ** and the RHS is not contant or has two or fewer terms, + ** then it is not worth creating an ephermeral table to evaluate + ** the IN operator so return IN_INDEX_NOOP. + */ + if( eType==0 + && (inFlags & IN_INDEX_NOOP_OK) + && !ExprHasProperty(pX, EP_xIsSelect) + && (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2) + ){ + eType = IN_INDEX_NOOP; + } + + if( eType==0 ){ /* Could not find an existing table or index to use as the RHS b-tree. ** We will have to generate an ephemeral table to do the job. @@ -1935,7 +1978,8 @@ static void sqlite3ExprCodeIN( v = pParse->pVdbe; assert( v!=0 ); /* OOM detected prior to this routine */ VdbeNoopComment((v, "begin IN expr")); - eType = sqlite3FindInIndex(pParse, pExpr, IN_INDEX_MEMBERSHIP, + eType = sqlite3FindInIndex(pParse, pExpr, + IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK, destIfFalse==destIfNull ? 0 : &rRhsHasNull); /* Figure out the affinity to use to create a key from the results @@ -1950,68 +1994,111 @@ static void sqlite3ExprCodeIN( r1 = sqlite3GetTempReg(pParse); sqlite3ExprCode(pParse, pExpr->pLeft, r1); - /* If the LHS is NULL, then the result is either false or NULL depending - ** on whether the RHS is empty or not, respectively. + /* If sqlite3FindInIndex() did not find or create an index that is + ** suitable for evaluating the IN operator, then evaluate using a + ** sequence of comparisons. */ - if( destIfNull==destIfFalse ){ - /* Shortcut for the common case where the false and NULL outcomes are - ** the same. */ + if( eType==IN_INDEX_NOOP ){ + ExprList *pList = pExpr->x.pList; + CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + int labelOk = sqlite3VdbeMakeLabel(v); + int r2, regToFree; + int regCkNull = 0; + int ii; + assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); + if( destIfNull!=destIfFalse ){ + regCkNull = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_Integer, 0, regCkNull); + } + for(ii=0; iinExpr; ii++){ + r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree); + if( regCkNull ){ + sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull); + } + if( iinExpr-1 || destIfNull!=destIfFalse ){ + sqlite3VdbeAddOp4(v, OP_Eq, r1, labelOk, r2, + (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, affinity); + }else{ + assert( destIfNull==destIfFalse ); + sqlite3VdbeAddOp4(v, OP_Ne, r1, destIfFalse, r2, + (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, affinity | SQLITE_JUMPIFNULL); + } + sqlite3ReleaseTempReg(pParse, regToFree); + } + if( regCkNull ){ + sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); + } + sqlite3VdbeResolveLabel(v, labelOk); + sqlite3ReleaseTempReg(pParse, regCkNull); }else{ - int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); - sqlite3VdbeJumpHere(v, addr1); - } - - if( eType==IN_INDEX_ROWID ){ - /* In this case, the RHS is the ROWID of table b-tree + + /* If the LHS is NULL, then the result is either false or NULL depending + ** on whether the RHS is empty or not, respectively. */ - sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1); - VdbeCoverage(v); - }else{ - /* In this case, the RHS is an index b-tree. - */ - sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); - - /* If the set membership test fails, then the result of the - ** "x IN (...)" expression must be either 0 or NULL. If the set - ** contains no NULL values, then the result is 0. If the set - ** contains one or more NULL values, then the result of the - ** expression is also NULL. - */ - assert( destIfFalse!=destIfNull || rRhsHasNull==0 ); - if( rRhsHasNull==0 ){ - /* This branch runs if it is known at compile time that the RHS - ** cannot contain NULL values. This happens as the result - ** of a "NOT NULL" constraint in the database schema. - ** - ** Also run this branch if NULL is equivalent to FALSE - ** for this particular IN operator. + if( destIfNull==destIfFalse ){ + /* Shortcut for the common case where the false and NULL outcomes are + ** the same. */ + sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); + }else{ + int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); + sqlite3VdbeJumpHere(v, addr1); + } + + if( eType==IN_INDEX_ROWID ){ + /* In this case, the RHS is the ROWID of table b-tree */ - sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1); + sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1); VdbeCoverage(v); }else{ - /* In this branch, the RHS of the IN might contain a NULL and - ** the presence of a NULL on the RHS makes a difference in the - ** outcome. + /* In this case, the RHS is an index b-tree. */ - int j1; - - /* First check to see if the LHS is contained in the RHS. If so, - ** then the answer is TRUE the presence of NULLs in the RHS does - ** not matter. If the LHS is not contained in the RHS, then the - ** answer is NULL if the RHS contains NULLs and the answer is - ** FALSE if the RHS is NULL-free. + sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); + + /* If the set membership test fails, then the result of the + ** "x IN (...)" expression must be either 0 or NULL. If the set + ** contains no NULL values, then the result is 0. If the set + ** contains one or more NULL values, then the result of the + ** expression is also NULL. */ - j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); - sqlite3VdbeJumpHere(v, j1); + assert( destIfFalse!=destIfNull || rRhsHasNull==0 ); + if( rRhsHasNull==0 ){ + /* This branch runs if it is known at compile time that the RHS + ** cannot contain NULL values. This happens as the result + ** of a "NOT NULL" constraint in the database schema. + ** + ** Also run this branch if NULL is equivalent to FALSE + ** for this particular IN operator. + */ + sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1); + VdbeCoverage(v); + }else{ + /* In this branch, the RHS of the IN might contain a NULL and + ** the presence of a NULL on the RHS makes a difference in the + ** outcome. + */ + int j1; + + /* First check to see if the LHS is contained in the RHS. If so, + ** then the answer is TRUE the presence of NULLs in the RHS does + ** not matter. If the LHS is not contained in the RHS, then the + ** answer is NULL if the RHS contains NULLs and the answer is + ** FALSE if the RHS is NULL-free. + */ + j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); + sqlite3VdbeJumpHere(v, j1); + } } } sqlite3ReleaseTempReg(pParse, r1); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 97fb2d46e4..784fd0fd93 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3598,11 +3598,13 @@ const char *sqlite3JournalModename(int); #define IN_INDEX_EPH 2 /* Search an ephemeral b-tree */ #define IN_INDEX_INDEX_ASC 3 /* Existing index ASCENDING */ #define IN_INDEX_INDEX_DESC 4 /* Existing index DESCENDING */ +#define IN_INDEX_NOOP 5 /* No table available. Use comparisons */ /* ** Allowed flags for the 3rd parameter to sqlite3FindInIndex(). */ -#define IN_INDEX_MEMBERSHIP 0x0001 /* IN operator used for membership test */ -#define IN_INDEX_LOOP 0x0002 /* IN operator used as a loop */ +#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ +#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ +#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ int sqlite3FindInIndex(Parse *, Expr *, u32, int*); #ifdef SQLITE_ENABLE_ATOMIC_WRITE diff --git a/test/in4.test b/test/in4.test index 0a4a75008b..a89961f82b 100644 --- a/test/in4.test +++ b/test/in4.test @@ -231,11 +231,11 @@ do_execsql_test in4-3.44 { SELECT * FROM t3 WHERE x IN (10); } {~/OpenEphemeral/} do_execsql_test in4-3.45 { - SELECT * FROM t3 WHERE x NOT IN (10,11); + SELECT * FROM t3 WHERE x NOT IN (10,11,99999); } {1 1 1} do_execsql_test in4-3.46 { EXPLAIN - SELECT * FROM t3 WHERE x NOT IN (10,11); + SELECT * FROM t3 WHERE x NOT IN (10,11,99999); } {/OpenEphemeral/} do_execsql_test in4-3.47 { SELECT * FROM t3 WHERE x NOT IN (10); diff --git a/test/tkt-80e031a00f.test b/test/tkt-80e031a00f.test index 95372abf04..af1d636eed 100644 --- a/test/tkt-80e031a00f.test +++ b/test/tkt-80e031a00f.test @@ -160,6 +160,10 @@ do_execsql_test tkt-80e031a00f.322 {SELECT 'b' IN t8} 1 do_execsql_test tkt-80e031a00f.323 {SELECT 'c' NOT IN t8} 0 do_execsql_test tkt-80e031a00f.324 {SELECT 'c' IN t8n} 1 do_execsql_test tkt-80e031a00f.325 {SELECT 'd' NOT IN t8n} 0 +do_execsql_test tkt-80e031a00f.326 {SELECT 'a' IN (NULL,'a')} 1 +do_execsql_test tkt-80e031a00f.327 {SELECT 'a' IN (NULL,'b')} {{}} +do_execsql_test tkt-80e031a00f.328 {SELECT 'a' NOT IN (NULL,'a')} 0 +do_execsql_test tkt-80e031a00f.329 {SELECT 'a' NOT IN (NULL,'b')} {{}} # # Row 4: do_execsql_test tkt-80e031a00f.400 {SELECT 1 IN (2,3,4,null)} {{}} From a976979b6e1c01dbdfaeaddee5b3c80fc924ef94 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 4 Aug 2014 16:39:39 +0000 Subject: [PATCH 18/25] Refinements to the enhanced IN-operator logic. FossilOrigin-Name: 92ba2821468ecbfac2469161d81c873de67b2243 --- manifest | 15 ++++++--------- manifest.uuid | 2 +- src/expr.c | 7 +++---- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index 0a8cdbcd1c..d358a967d8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhancements\sto\sthe\scode\sgenerator\sfor\sthe\sIN\soperator\sthat\sresult\sin\smuch\nfaster\squeries\sin\ssome\scases,\sfor\sexample\swhen\sthe\sRHS\sof\sthe\sIN\soperator\nchanges\sfor\seach\srow\sof\sa\slarge\stable\sscan. -D 2014-08-02T21:03:33.699 +C Refinements\sto\sthe\senhanced\sIN-operator\slogic. +D 2014-08-04T16:39:39.657 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 89574df1ed8ca967fdd5be0e370722e508b91c2b +F src/expr.c 8f5e763623d79e71d60998a4e714324ca0e9380d F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -1185,10 +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 ba7826542908eac2e14789d183d0b3e35b143fed -R 93a5c3d553517a616682ed62728bfb2c -T *branch * IN-operator-improvements -T *sym-IN-operator-improvements * -T -sym-trunk * +P 436e884215e2b33ca3fbb555362237b12827c07a +R 0000d96605770a7d4078c73a9916f937 U drh -Z c474e62d8861a07a170ddf9e71c3b1a9 +Z 246e982e6330087cd1ec561e7d991220 diff --git a/manifest.uuid b/manifest.uuid index 0ddf2ad117..01804c86aa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -436e884215e2b33ca3fbb555362237b12827c07a \ No newline at end of file +92ba2821468ecbfac2469161d81c873de67b2243 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 7565d41b90..86787a9c34 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2006,14 +2006,13 @@ static void sqlite3ExprCodeIN( int regCkNull = 0; int ii; assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); - sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); if( destIfNull!=destIfFalse ){ regCkNull = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp2(v, OP_Integer, 0, regCkNull); + sqlite3VdbeAddOp3(v, OP_BitAnd, r1, r1, regCkNull); } for(ii=0; iinExpr; ii++){ r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree); - if( regCkNull ){ + if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){ sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull); } if( iinExpr-1 || destIfNull!=destIfFalse ){ @@ -2722,7 +2721,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ addr = sqlite3VdbeAddOp1(v, op, r1); VdbeCoverageIf(v, op==TK_ISNULL); VdbeCoverageIf(v, op==TK_NOTNULL); - sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); + sqlite3VdbeAddOp2(v, OP_Integer, 0, target); sqlite3VdbeJumpHere(v, addr); break; } From 7248a8b2b95a99d7fb7af7e5a3481f9cfcb95e3e Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 4 Aug 2014 18:50:54 +0000 Subject: [PATCH 19/25] Further enhancements to IN-operator processing. FossilOrigin-Name: 7fdf26da1d2f40b80f9e44ff6f5af22ace8f95f3 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/expr.c | 25 +++++++++++++++---------- src/update.c | 5 +++-- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index d358a967d8..a6de05b0b9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Refinements\sto\sthe\senhanced\sIN-operator\slogic. -D 2014-08-04T16:39:39.657 +C Further\senhancements\sto\sIN-operator\sprocessing. +D 2014-08-04T18:50:54.734 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 8f5e763623d79e71d60998a4e714324ca0e9380d +F src/expr.c 8ac2d0e8a0c1bc84eba94ab39867ba4d07d84f75 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -279,7 +279,7 @@ F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c ae45399d6252b4d736af43bee1576ce7bff86aec F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb -F src/update.c 01564b3c430f6c7b0a35afaf7aba7987206fa3a5 +F src/update.c 510c59a21bd8ba315db173b38d79688cc15261df F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05 F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 @@ -1185,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 436e884215e2b33ca3fbb555362237b12827c07a -R 0000d96605770a7d4078c73a9916f937 +P 92ba2821468ecbfac2469161d81c873de67b2243 +R d7c5ed9f11c47855b5c64fea1267f119 U drh -Z 246e982e6330087cd1ec561e7d991220 +Z 6f0f219998d1d32472de07ef9dc89d8e diff --git a/manifest.uuid b/manifest.uuid index 01804c86aa..bf4d5ed437 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -92ba2821468ecbfac2469161d81c873de67b2243 \ No newline at end of file +7fdf26da1d2f40b80f9e44ff6f5af22ace8f95f3 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 86787a9c34..6816d560d3 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1368,6 +1368,9 @@ int sqlite3ExprCanBeNull(const Expr *p){ case TK_FLOAT: case TK_BLOB: return 0; + case TK_COLUMN: + assert( p->pTab!=0 ); + return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0; default: return 1; } @@ -2038,16 +2041,18 @@ static void sqlite3ExprCodeIN( /* If the LHS is NULL, then the result is either false or NULL depending ** on whether the RHS is empty or not, respectively. */ - if( destIfNull==destIfFalse ){ - /* Shortcut for the common case where the false and NULL outcomes are - ** the same. */ - sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); - }else{ - int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); - sqlite3VdbeJumpHere(v, addr1); + if( sqlite3ExprCanBeNull(pExpr->pLeft) ){ + if( destIfNull==destIfFalse ){ + /* Shortcut for the common case where the false and NULL outcomes are + ** the same. */ + sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); + }else{ + int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); + VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull); + sqlite3VdbeJumpHere(v, addr1); + } } if( eType==IN_INDEX_ROWID ){ diff --git a/src/update.c b/src/update.c index 3e04e00316..fe717a2ac1 100644 --- a/src/update.c +++ b/src/update.c @@ -437,8 +437,9 @@ void sqlite3Update( VdbeCoverageNeverTaken(v); } labelContinue = labelBreak; - sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); - VdbeCoverage(v); + if( pPk==0 ){ + sqlite3VdbeAddOp2(v, OP_IsNull, regOldRowid, labelBreak); VdbeCoverage(v); + } }else if( pPk ){ labelContinue = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); From 2c3ea0694feef861c13fb4e3ff818558d4655be8 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 4 Aug 2014 21:26:58 +0000 Subject: [PATCH 20/25] Part of the change in the previous check-in was incorrect and can result in an incorrect UPDATE for WITHOUT ROWID tables. This check-in fixes the problem. FossilOrigin-Name: ee5f6eae57a656d09a4b3f7fbef664b2c696ddb4 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/update.c | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index a6de05b0b9..6f9201a593 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Further\senhancements\sto\sIN-operator\sprocessing. -D 2014-08-04T18:50:54.734 +C Part\sof\sthe\schange\sin\sthe\sprevious\scheck-in\swas\sincorrect\sand\scan\sresult\nin\san\sincorrect\sUPDATE\sfor\sWITHOUT\sROWID\stables.\s\sThis\scheck-in\sfixes\sthe\nproblem. +D 2014-08-04T21:26:58.927 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -279,7 +279,7 @@ F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/tokenize.c ae45399d6252b4d736af43bee1576ce7bff86aec F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb -F src/update.c 510c59a21bd8ba315db173b38d79688cc15261df +F src/update.c ea336ce7b8b3fc5e316ba8f082e6445babf81059 F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05 F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 @@ -1185,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 92ba2821468ecbfac2469161d81c873de67b2243 -R d7c5ed9f11c47855b5c64fea1267f119 +P 7fdf26da1d2f40b80f9e44ff6f5af22ace8f95f3 +R bbb8ed3fbc770a15faae84bee68a96b7 U drh -Z 6f0f219998d1d32472de07ef9dc89d8e +Z dee92a9842f8b9e58ec243da3f9d9eb9 diff --git a/manifest.uuid b/manifest.uuid index bf4d5ed437..9bd8699697 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7fdf26da1d2f40b80f9e44ff6f5af22ace8f95f3 \ No newline at end of file +ee5f6eae57a656d09a4b3f7fbef664b2c696ddb4 \ No newline at end of file diff --git a/src/update.c b/src/update.c index fe717a2ac1..e152e9057c 100644 --- a/src/update.c +++ b/src/update.c @@ -437,9 +437,9 @@ void sqlite3Update( VdbeCoverageNeverTaken(v); } labelContinue = labelBreak; - if( pPk==0 ){ - sqlite3VdbeAddOp2(v, OP_IsNull, regOldRowid, labelBreak); VdbeCoverage(v); - } + sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); + VdbeCoverageIf(v, pPk==0); + VdbeCoverageIf(v, pPk!=0); }else if( pPk ){ labelContinue = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); From 4336b0e64a42bbf3f7a97511805a300797c681fd Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 5 Aug 2014 00:53:51 +0000 Subject: [PATCH 21/25] Improved VdbeCoverage() macros. A few minor simplifications to generated VDBE code. FossilOrigin-Name: 01f60027ad1841051fa493a646141445f8971357 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/expr.c | 4 +++- src/pragma.c | 11 +++++------ src/select.c | 3 +-- src/vdbe.c | 20 +++++++++++--------- 6 files changed, 30 insertions(+), 28 deletions(-) diff --git a/manifest b/manifest index 6f9201a593..e1ddd56052 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Part\sof\sthe\schange\sin\sthe\sprevious\scheck-in\swas\sincorrect\sand\scan\sresult\nin\san\sincorrect\sUPDATE\sfor\sWITHOUT\sROWID\stables.\s\sThis\scheck-in\sfixes\sthe\nproblem. -D 2014-08-04T21:26:58.927 +C Improved\sVdbeCoverage()\smacros.\s\sA\sfew\sminor\ssimplifications\sto\sgenerated\nVDBE\scode. +D 2014-08-05T00:53:51.727 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 8ac2d0e8a0c1bc84eba94ab39867ba4d07d84f75 +F src/expr.c ef474fc0e73a2fc14835a2dc5282d3c28f8e1eaa F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -216,13 +216,13 @@ F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0 F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c -F src/pragma.c d4a33151f057e35e5a2024adf8e41d2817b5c105 +F src/pragma.c d10ef67c4de79f78188b965b4b7988aff1d66f2e F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337 F src/printf.c af06f66927919730f03479fed6ae9854f73419f4 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece F src/resolve.c 5fc110baeacf120a73fe34e103f052632ff11a02 F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be -F src/select.c 6762c62e11b504aa014edceab8886495165e3a77 +F src/select.c 1529c49075464c5a95fde77314073612b1b8d595 F src/shell.c 191129c3f7a9cf241aea90ff6a6be3e74d3767f0 F src/sqlite.h.in 9bbc5815c73b0e77e68b5275481a5e3e7814a804 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e @@ -283,7 +283,7 @@ F src/update.c ea336ce7b8b3fc5e316ba8f082e6445babf81059 F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05 F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c b9e6866e43a61ca4080410f27c4bb52823495186 +F src/vdbe.c aa93cf7a215a37d1c7ae565202a44869c78dbf8d F src/vdbe.h c63fad052c9e7388d551e556e119c0bcf6bebdf8 F src/vdbeInt.h f5513f2b5ac1e2c5128996c7ea23add256a301df F src/vdbeapi.c 24e40422382beb774daab11fe9fe9d37e8a04949 @@ -1185,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 7fdf26da1d2f40b80f9e44ff6f5af22ace8f95f3 -R bbb8ed3fbc770a15faae84bee68a96b7 +P ee5f6eae57a656d09a4b3f7fbef664b2c696ddb4 +R 05961687f6977550c21111dd4304208a U drh -Z dee92a9842f8b9e58ec243da3f9d9eb9 +Z b7d896cc5839c70221fa827c578afa41 diff --git a/manifest.uuid b/manifest.uuid index 9bd8699697..c10e21e526 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ee5f6eae57a656d09a4b3f7fbef664b2c696ddb4 \ No newline at end of file +01f60027ad1841051fa493a646141445f8971357 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 6816d560d3..e6ac84db94 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2020,7 +2020,9 @@ static void sqlite3ExprCodeIN( } if( iinExpr-1 || destIfNull!=destIfFalse ){ sqlite3VdbeAddOp4(v, OP_Eq, r1, labelOk, r2, - (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); + (void*)pColl, P4_COLLSEQ); + VdbeCoverageIf(v, iinExpr-1); + VdbeCoverageIf(v, ii==pList->nExpr-1); sqlite3VdbeChangeP5(v, affinity); }else{ assert( destIfNull==destIfFalse ); diff --git a/src/pragma.c b/src/pragma.c index b37499f7bd..9ed5e13eb0 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1794,9 +1794,8 @@ void sqlite3Pragma( */ static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList endCode[] = { - { OP_AddImm, 1, 0, 0}, /* 0 */ - { OP_IfNeg, 1, 0, 0}, /* 1 */ - { OP_String8, 0, 3, 0}, /* 2 */ + { OP_IfNeg, 1, 0, 0}, /* 0 */ + { OP_String8, 0, 3, 0}, /* 1 */ { OP_ResultRow, 3, 1, 0}, }; @@ -2002,9 +2001,9 @@ void sqlite3Pragma( } } addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); - sqlite3VdbeChangeP2(v, addr, -mxErr); - sqlite3VdbeJumpHere(v, addr+1); - sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC); + sqlite3VdbeChangeP3(v, addr, -mxErr); + sqlite3VdbeJumpHere(v, addr); + sqlite3VdbeChangeP4(v, addr+1, "ok", P4_STATIC); } break; #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ diff --git a/src/select.c b/src/select.c index 6ceb3fe946..f5456c893d 100644 --- a/src/select.c +++ b/src/select.c @@ -541,8 +541,7 @@ static void codeOffset( ){ if( iOffset>0 ){ int addr; - sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1); - addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v); + addr = sqlite3VdbeAddOp3(v, OP_IfNeg, iOffset, 0, -1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue); VdbeComment((v, "skip OFFSET records")); sqlite3VdbeJumpHere(v, addr); diff --git a/src/vdbe.c b/src/vdbe.c index ade82b054a..16d9eee969 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -116,6 +116,12 @@ int sqlite3_found_count = 0; ** branch can go. It is usually 2. "I" is the direction the branch ** goes. 0 means falls through. 1 means branch is taken. 2 means the ** second alternative branch is taken. +** +** iSrcLine is the source code line (from the __LINE__ macro) that +** generated the VDBE instruction. This instrumentation assumes that all +** source code is in a single file (the amalgamation). Special values 1 +** and 2 for the iSrcLine parameter mean that this particular branch is +** always taken or never taken, respectively. */ #if !defined(SQLITE_VDBE_COVERAGE) # define VdbeBranchTaken(I,M) @@ -5600,17 +5606,16 @@ case OP_IfPos: { /* jump, in1 */ break; } -/* Opcode: IfNeg P1 P2 * * * -** Synopsis: if r[P1]<0 goto P2 +/* Opcode: IfNeg P1 P2 P3 * * +** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2 ** -** If the value of register P1 is less than zero, jump to P2. -** -** It is illegal to use this instruction on a register that does -** not contain an integer. An assertion fault will result if you try. +** Register P1 must contain an intger. Add literal P3 to the value in +** register P1 then if the value of register P1 is less than zero, jump to P2. */ case OP_IfNeg: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); + pIn1->u.i += pOp->p3; VdbeBranchTaken(pIn1->u.i<0, 2); if( pIn1->u.i<0 ){ pc = pOp->p2 - 1; @@ -5623,9 +5628,6 @@ case OP_IfNeg: { /* jump, in1 */ ** ** The register P1 must contain an integer. Add literal P3 to the ** value in register P1. If the result is exactly 0, jump to P2. -** -** It is illegal to use this instruction on a register that does -** not contain an integer. An assertion fault will result if you try. */ case OP_IfZero: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; From 2c5e35ffd159686bdba701a561292beee4351781 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 5 Aug 2014 11:04:21 +0000 Subject: [PATCH 22/25] Rename the internal Schema.flags field to Schema.schemaFlags. FossilOrigin-Name: 5ae80b3c8f032528359c8c762505ce24da8db96f --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/btree.c | 2 +- src/build.c | 2 +- src/callback.c | 4 ++-- src/sqliteInt.h | 10 +++++----- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index ae65d8580f..2e9232ccf3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\s(newly)\sincorrect\spreprocessor\scheck\sto\sfix\sbuild\son\sWinRT. -D 2014-08-02T20:44:13.563 +C Rename\sthe\sinternal\sSchema.flags\sfield\sto\sSchema.schemaFlags. +D 2014-08-05T11:04:21.126 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -167,11 +167,11 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c b5531339cd826af46b9621e4a9323971a9380e12 +F src/btree.c 99d162e57af6e72ffd7db5bf79568a134cd87d5b F src/btree.h 4245a349bfe09611d7ff887dbc3a80cee8b7955a F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3 -F src/build.c c67a915cd5aabda9ac170f2af8ea25434476b66f -F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98 +F src/build.c 5abf794fe8a605f2005b422e98a3cedad9b9ef5b +F src/callback.c fcff28cf0df2403dd2f313bb8d1b8f31f6f3cd64 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 @@ -227,7 +227,7 @@ F src/shell.c 191129c3f7a9cf241aea90ff6a6be3e74d3767f0 F src/sqlite.h.in 9bbc5815c73b0e77e68b5275481a5e3e7814a804 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 5cee19f34f6efe6e6f7733d55a5c59e3a35a378a +F src/sqliteInt.h 85c03beef501eb79db37f7d963597810aaa581a5 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -1185,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 9bc1c730a366e75b760b58e7a343d39165b2a469 -R 8c9bd54f21254a5c39cdbf67a68f6f01 -U mistachkin -Z a3832f522ef0a90c3ccd915e060c6930 +P ba7826542908eac2e14789d183d0b3e35b143fed +R 5db7ff3ac4350fd50475a1b030dd8291 +U drh +Z 42ccecdc76986fb0ef00d15b10cbc956 diff --git a/manifest.uuid b/manifest.uuid index d8a5cdba49..01721976cd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ba7826542908eac2e14789d183d0b3e35b143fed \ No newline at end of file +5ae80b3c8f032528359c8c762505ce24da8db96f \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index b72a2ab01d..17719caf91 100644 --- a/src/btree.c +++ b/src/btree.c @@ -162,7 +162,7 @@ static int hasSharedCacheTableLock( ** the correct locks are held. So do not bother - just return true. ** This case does not come up very often anyhow. */ - if( isIndex && (!pSchema || (pSchema->flags&DB_SchemaLoaded)==0) ){ + if( isIndex && (!pSchema || (pSchema->schemaFlags&DB_SchemaLoaded)==0) ){ return 1; } diff --git a/src/build.c b/src/build.c index 28205c4c61..a9a8f21793 100644 --- a/src/build.c +++ b/src/build.c @@ -2130,7 +2130,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ pSelTab->aCol = 0; sqlite3DeleteTable(db, pSelTab); assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); - pTable->pSchema->flags |= DB_UnresetViews; + pTable->pSchema->schemaFlags |= DB_UnresetViews; }else{ pTable->nCol = 0; nErr++; diff --git a/src/callback.c b/src/callback.c index 260fe806bb..46fbe2c21a 100644 --- a/src/callback.c +++ b/src/callback.c @@ -447,9 +447,9 @@ void sqlite3SchemaClear(void *p){ sqlite3HashClear(&temp1); sqlite3HashClear(&pSchema->fkeyHash); pSchema->pSeqTab = 0; - if( pSchema->flags & DB_SchemaLoaded ){ + if( pSchema->schemaFlags & DB_SchemaLoaded ){ pSchema->iGeneration++; - pSchema->flags &= ~DB_SchemaLoaded; + pSchema->schemaFlags &= ~DB_SchemaLoaded; } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 97fb2d46e4..ed9f44584d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -876,7 +876,7 @@ struct Schema { Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ - u16 flags; /* Flags associated with this schema */ + u16 schemaFlags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ }; @@ -884,10 +884,10 @@ struct Schema { ** These macros can be used to test, set, or clear bits in the ** Db.pSchema->flags field. */ -#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P)) -#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0) -#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P) -#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P) +#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P)) +#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))!=0) +#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags|=(P) +#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags&=~(P) /* ** Allowed values for the DB.pSchema->flags field. From 1cfc9aa993ee0210d71b6c58c81f2a20c5590b7e Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 5 Aug 2014 21:31:08 +0000 Subject: [PATCH 23/25] Ensure that aggregate functions are not used when evaluating a default value for a table column. Candidate fix for ticket [3a88d85f36704eebe134f7]. FossilOrigin-Name: 29ba812825bf06ef230f2480bba0579653f0a52d --- manifest | 15 +++++++-------- manifest.uuid | 2 +- src/expr.c | 5 +++++ test/table.test | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index f744c3e087..9183753c67 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sability\sto\sevaluate\sIN\soperators\sas\sa\ssequence\sof\scomparisons\sas\nan\salternative\sto\sthe\slong-standing\salgorithm\sof\sbuilding\sa\slookup\stable.\nUse\sthe\snew\simplementation\sin\scircumstances\swhere\sit\sis\slikely\sto\sbe\sfaster,\nsuch\sas\swhen\sthe\sRHS\sof\sthe\sIN\schanges\sbetween\ssuccessive\sevaluations. -D 2014-08-05T19:16:22.008 +C Ensure\sthat\saggregate\sfunctions\sare\snot\sused\swhen\sevaluating\sa\sdefault\nvalue\sfor\sa\stable\scolumn.\nCandidate\sfix\sfor\sticket\s[3a88d85f36704eebe134f7]. +D 2014-08-05T21:31:08.768 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c ef474fc0e73a2fc14835a2dc5282d3c28f8e1eaa +F src/expr.c 94d26c8e47bb25957e3963cc3d116b09ed8e12cd F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -856,7 +856,7 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85 F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6 -F test/table.test 580d23530187026d4502fae74a490f0408cf2cc7 +F test/table.test 5b985827973a7b7b24ce155c8bda5fe3544e8442 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43 @@ -1185,8 +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 5ae80b3c8f032528359c8c762505ce24da8db96f 01f60027ad1841051fa493a646141445f8971357 -R c68854702374dc69a486e042d017018d -T +closed 01f60027ad1841051fa493a646141445f8971357 +P 952868216854e8355edf57af62bd1a6bcb70ce61 +R cc49bc1b5436eaa2e754c5d5e9ba9fd5 U drh -Z d50dbb21b6962a7518b2d56fd33bd762 +Z 79f28300cbbdd20d7d6bedff33de2779 diff --git a/manifest.uuid b/manifest.uuid index 130e8a5420..b2aee10dd3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -952868216854e8355edf57af62bd1a6bcb70ce61 \ No newline at end of file +29ba812825bf06ef230f2480bba0579653f0a52d \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index e6ac84db94..9eb893d265 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2768,6 +2768,11 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId); break; } + if( pDef->xFunc==0 ){ + sqlite3ErrorMsg(pParse, "misuse of aggregate function: %.*s()", + nId, zId); + break; + } /* Attempt a direct implementation of the built-in COALESCE() and ** IFNULL() functions. This avoids unnecessary evalation of diff --git a/test/table.test b/test/table.test index ed9efc02cd..777cc1723d 100644 --- a/test/table.test +++ b/test/table.test @@ -726,4 +726,50 @@ do_test table-15.2 { execsql {COMMIT} } {} +# Ticket 3a88d85f36704eebe134f7f48aebf00cd6438c1a (2014-08-05) +# The following SQL script segfaults while running the INSERT statement: +# +# CREATE TABLE t1(x DEFAULT(max(1))); +# INSERT INTO t1(rowid) VALUES(1); +# +# The problem appears to be the use of an aggregate function as part of +# the default value for a column. This problem has been in the code since +# at least 2006-01-01 and probably before that. This problem was detected +# and reported on the sqlite-users@sqlite.org mailing list by Zsbán Ambrus. +# +do_execsql_test table-16.1 { + CREATE TABLE t16(x DEFAULT(max(1))); + INSERT INTO t16(x) VALUES(123); + SELECT rowid, x FROM t16; +} {1 123} +do_catchsql_test table-16.2 { + INSERT INTO t16(rowid) VALUES(4); +} {1 {misuse of aggregate function: max()}} +do_execsql_test table-16.3 { + DROP TABLE t16; + CREATE TABLE t16(x DEFAULT(abs(1))); + INSERT INTO t16(rowid) VALUES(4); + SELECT rowid, x FROM t16; +} {4 1} +do_catchsql_test table-16.4 { + DROP TABLE t16; + CREATE TABLE t16(x DEFAULT(avg(1))); + INSERT INTO t16(rowid) VALUES(123); + SELECT rowid, x FROM t16; +} {1 {misuse of aggregate function: avg()}} +do_catchsql_test table-16.5 { + DROP TABLE t16; + CREATE TABLE t16(x DEFAULT(count())); + INSERT INTO t16(rowid) VALUES(123); + SELECT rowid, x FROM t16; +} {1 {misuse of aggregate function: count()}} +do_catchsql_test table-16.6 { + DROP TABLE t16; + CREATE TABLE t16(x DEFAULT(group_concat('x',','))); + INSERT INTO t16(rowid) VALUES(123); + SELECT rowid, x FROM t16; +} {1 {misuse of aggregate function: group_concat()}} + + + finish_test From 0c4de2d96de879f19e4ff8f952a82713c9a9c18b Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 6 Aug 2014 00:29:06 +0000 Subject: [PATCH 24/25] A simpler fix for ticket [3a88d85f36704eebe1] - one that uses less code. The error message is not quite as good, but as this error has apparently not previously occurred in over 8 years of heavy use, that is not seen as a serious problem. FossilOrigin-Name: 0ad1ed8ef0b5fb5d8db44479373b2b93d8fcfd66 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/expr.c | 7 +------ test/table.test | 13 +++++++------ 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 9183753c67..829712eb8e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\sthat\saggregate\sfunctions\sare\snot\sused\swhen\sevaluating\sa\sdefault\nvalue\sfor\sa\stable\scolumn.\nCandidate\sfix\sfor\sticket\s[3a88d85f36704eebe134f7]. -D 2014-08-05T21:31:08.768 +C A\ssimpler\sfix\sfor\sticket\s[3a88d85f36704eebe1]\s-\sone\sthat\suses\sless\scode.\nThe\serror\smessage\sis\snot\squite\sas\sgood,\sbut\sas\sthis\serror\shas\sapparently\nnot\spreviously\soccurred\sin\sover\s8\syears\sof\sheavy\suse,\sthat\sis\snot\sseen\sas\na\sserious\sproblem. +D 2014-08-06T00:29:06.807 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -176,7 +176,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf -F src/expr.c 94d26c8e47bb25957e3963cc3d116b09ed8e12cd +F src/expr.c f749009cf4a8534efb5e0d5cd7c9fb1fb0f2836c F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514 F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc @@ -856,7 +856,7 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85 F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6 -F test/table.test 5b985827973a7b7b24ce155c8bda5fe3544e8442 +F test/table.test 2a1d2fa52c531de5915f28023747d9a8c27b6f31 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43 @@ -1185,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 952868216854e8355edf57af62bd1a6bcb70ce61 -R cc49bc1b5436eaa2e754c5d5e9ba9fd5 +P 29ba812825bf06ef230f2480bba0579653f0a52d +R f634869bc839ef6a8575d1173c369416 U drh -Z 79f28300cbbdd20d7d6bedff33de2779 +Z 8e016893764edede1871bf058b88fac4 diff --git a/manifest.uuid b/manifest.uuid index b2aee10dd3..741aa44ffb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -29ba812825bf06ef230f2480bba0579653f0a52d \ No newline at end of file +0ad1ed8ef0b5fb5d8db44479373b2b93d8fcfd66 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 9eb893d265..0d2292e943 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2764,15 +2764,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0); - if( pDef==0 ){ + if( pDef==0 || pDef->xFunc==0 ){ sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId); break; } - if( pDef->xFunc==0 ){ - sqlite3ErrorMsg(pParse, "misuse of aggregate function: %.*s()", - nId, zId); - break; - } /* Attempt a direct implementation of the built-in COALESCE() and ** IFNULL() functions. This avoids unnecessary evalation of diff --git a/test/table.test b/test/table.test index 777cc1723d..656884ca73 100644 --- a/test/table.test +++ b/test/table.test @@ -744,7 +744,7 @@ do_execsql_test table-16.1 { } {1 123} do_catchsql_test table-16.2 { INSERT INTO t16(rowid) VALUES(4); -} {1 {misuse of aggregate function: max()}} +} {1 {unknown function: max()}} do_execsql_test table-16.3 { DROP TABLE t16; CREATE TABLE t16(x DEFAULT(abs(1))); @@ -756,20 +756,21 @@ do_catchsql_test table-16.4 { CREATE TABLE t16(x DEFAULT(avg(1))); INSERT INTO t16(rowid) VALUES(123); SELECT rowid, x FROM t16; -} {1 {misuse of aggregate function: avg()}} +} {1 {unknown function: avg()}} do_catchsql_test table-16.5 { DROP TABLE t16; CREATE TABLE t16(x DEFAULT(count())); INSERT INTO t16(rowid) VALUES(123); SELECT rowid, x FROM t16; -} {1 {misuse of aggregate function: count()}} +} {1 {unknown function: count()}} do_catchsql_test table-16.6 { DROP TABLE t16; CREATE TABLE t16(x DEFAULT(group_concat('x',','))); INSERT INTO t16(rowid) VALUES(123); SELECT rowid, x FROM t16; -} {1 {misuse of aggregate function: group_concat()}} - - +} {1 {unknown function: group_concat()}} +do_catchsql_test table-16.7 { + INSERT INTO t16 DEFAULT VALUES; +} {1 {unknown function: group_concat()}} finish_test From bc5cf3813ea1bf56ed19a35028061e779827fffc Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 6 Aug 2014 01:08:07 +0000 Subject: [PATCH 25/25] Fix typos in the opcode documentation. Comment changes only. No changes to code. FossilOrigin-Name: 717245d48714c08156c9b7636aaa6c3a402bad66 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbe.c | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index 829712eb8e..a945d8dafc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C A\ssimpler\sfix\sfor\sticket\s[3a88d85f36704eebe1]\s-\sone\sthat\suses\sless\scode.\nThe\serror\smessage\sis\snot\squite\sas\sgood,\sbut\sas\sthis\serror\shas\sapparently\nnot\spreviously\soccurred\sin\sover\s8\syears\sof\sheavy\suse,\sthat\sis\snot\sseen\sas\na\sserious\sproblem. -D 2014-08-06T00:29:06.807 +C Fix\stypos\sin\sthe\sopcode\sdocumentation.\s\sComment\schanges\sonly.\s\sNo\schanges\nto\scode. +D 2014-08-06T01:08:07.269 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -283,7 +283,7 @@ F src/update.c ea336ce7b8b3fc5e316ba8f082e6445babf81059 F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05 F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c aa93cf7a215a37d1c7ae565202a44869c78dbf8d +F src/vdbe.c 2db817cf7c51fa775ecc68160352aefc3d9870f7 F src/vdbe.h c63fad052c9e7388d551e556e119c0bcf6bebdf8 F src/vdbeInt.h f5513f2b5ac1e2c5128996c7ea23add256a301df F src/vdbeapi.c 24e40422382beb774daab11fe9fe9d37e8a04949 @@ -1185,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 29ba812825bf06ef230f2480bba0579653f0a52d -R f634869bc839ef6a8575d1173c369416 +P 0ad1ed8ef0b5fb5d8db44479373b2b93d8fcfd66 +R 1045cc0c95f68e0f0e2e47642b0ec158 U drh -Z 8e016893764edede1871bf058b88fac4 +Z fecab6dfa8d111d2725130892a38124f diff --git a/manifest.uuid b/manifest.uuid index 741aa44ffb..c81900087c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0ad1ed8ef0b5fb5d8db44479373b2b93d8fcfd66 \ No newline at end of file +717245d48714c08156c9b7636aaa6c3a402bad66 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 16d9eee969..6c46d76569 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -796,7 +796,7 @@ case OP_InitCoroutine: { /* jump */ /* Opcode: EndCoroutine P1 * * * * ** -** The instruction at the address in register P1 is an Yield. +** The instruction at the address in register P1 is a Yield. ** Jump to the P2 parameter of that Yield. ** After the jump, register P1 becomes undefined. ** @@ -989,7 +989,7 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */ ** Synopsis: r[P2]='P4' ** ** P4 points to a nul terminated UTF-8 string. This opcode is transformed -** into an OP_String before it is executed for the first time. During +** into a String before it is executed for the first time. During ** this transformation, the length of string P4 is computed and stored ** as the P1 parameter. */ @@ -3513,7 +3513,7 @@ case OP_Close: { ** greater than or equal to the key and P2 is not zero, then jump to P2. ** ** This opcode leaves the cursor configured to move in forward order, -** from the begining toward the end. In other words, the cursor is +** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. ** ** See also: Found, NotFound, SeekLt, SeekGt, SeekLe @@ -4217,7 +4217,7 @@ case OP_InsertInt: { ** The cursor will be left pointing at either the next or the previous ** record in the table. If it is left pointing at the next record, then ** the next Next instruction will be a no-op. Hence it is OK to delete -** a record from within an Next loop. +** a record from within a Next loop. ** ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is ** incremented (otherwise not). @@ -4280,7 +4280,7 @@ case OP_ResetCount: { ** 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 +** record blob in register P3 against a prefix of the entry that ** the sorter cursor currently points to. Only the first P4 fields ** of r[P3] and the sorter record are compared. ** @@ -5609,7 +5609,7 @@ case OP_IfPos: { /* jump, in1 */ /* Opcode: IfNeg P1 P2 P3 * * ** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2 ** -** Register P1 must contain an intger. Add literal P3 to the value in +** Register P1 must contain an integer. Add literal P3 to the value in ** register P1 then if the value of register P1 is less than zero, jump to P2. */ case OP_IfNeg: { /* jump, in1 */