diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index b1a931a9df1..60b54a2ed99 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -788,7 +788,8 @@ static void die(const char* fmt, ...) fprintf(stderr, "\n"); va_end(args); cleanup(); - my_end(0); + /* We cannot free DBUG, it is used in global destructors after exit(). */ + my_end(MY_DONT_FREE_DBUG); exit(1); } @@ -1460,7 +1461,8 @@ int main(int argc, char** argv) cleanup(); free_defaults(defaults_argv); my_free_open_file_info(); - my_end(0); + /* We cannot free DBUG, it is used in global destructors after exit(). */ + my_end(MY_DONT_FREE_DBUG); exit(exit_value); DBUG_RETURN(exit_value); // Keep compilers happy } diff --git a/dbug/dbug.c b/dbug/dbug.c index 91b7e7b6c4c..c991daf3617 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -271,6 +271,8 @@ static unsigned long Clock (void); static void CloseFile(FILE *fp); /* Push current debug state */ static void PushState(void); + /* Free memory associated with debug state. */ +static void FreeState (struct state *state); /* Test for tracing enabled */ static BOOLEAN DoTrace(CODE_STATE *state); /* Test to see if file is writable */ @@ -630,22 +632,7 @@ void _db_pop_ () stack = discard -> next_state; _db_fp_ = stack -> out_file; _db_pfp_ = stack -> prof_file; - if (discard -> keywords != NULL) { - FreeList (discard -> keywords); - } - if (discard -> functions != NULL) { - FreeList (discard -> functions); - } - if (discard -> processes != NULL) { - FreeList (discard -> processes); - } - if (discard -> p_functions != NULL) { - FreeList (discard -> p_functions); - } - CloseFile (discard -> out_file); - if (discard -> prof_file) - CloseFile (discard -> prof_file); - free ((char *) discard); + FreeState(discard); if (!(stack->flags & DEBUG_ON)) _db_on_=0; } @@ -1160,6 +1147,71 @@ static void PushState () stack=new_malloc; } +/* + * FUNCTION + * + * FreeState Free memory associated with a struct state. + * + * SYNOPSIS + * + * static void FreeState (state) + * struct state *state; + * + * DESCRIPTION + * + * Deallocates the memory allocated for various information in a + * state. + * + */ +static void FreeState ( +struct state *state) +{ + if (state -> keywords != NULL) { + FreeList (state -> keywords); + } + if (state -> functions != NULL) { + FreeList (state -> functions); + } + if (state -> processes != NULL) { + FreeList (state -> processes); + } + if (state -> p_functions != NULL) { + FreeList (state -> p_functions); + } + CloseFile (state -> out_file); + if (state -> prof_file) + CloseFile (state -> prof_file); + free ((char *) state); +} + + +/* + * FUNCTION + * + * _db_end_ End debugging, freeing state stack memory. + * + * SYNOPSIS + * + * static VOID _db_end_ () + * + * DESCRIPTION + * + * Ends debugging, de-allocating the memory allocated to the + * state stack. + * + * To be called at the very end of the program. + * + */ +void _db_end_ () +{ + reg1 struct state *discard; + while((discard= stack) != NULL) { + stack= discard -> next_state; + FreeState (discard); + } + _db_on_=0; +} + /* * FUNCTION diff --git a/include/my_dbug.h b/include/my_dbug.h index b76a3fcc8c9..6e60b599f53 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -40,6 +40,7 @@ extern void _db_doprnt_ _VARARGS((const char *format,...)); extern void _db_dump_(uint _line_,const char *keyword,const char *memory, uint length); extern void _db_output_(uint flag); +extern void _db_end_(void); extern void _db_lock_file(void); extern void _db_unlock_file(void); @@ -66,6 +67,7 @@ extern void _db_unlock_file(void); #define DBUG_IN_USE (_db_fp_ && _db_fp_ != stderr) #define DEBUGGER_OFF _no_db_=1;_db_on_=0; #define DEBUGGER_ON _no_db_=0 +#define DBUG_END() _db_end_ () #define DBUG_LOCK_FILE { _db_lock_file(); } #define DBUG_UNLOCK_FILE { _db_unlock_file(); } #define DBUG_OUTPUT(A) { _db_output_(A); } @@ -90,6 +92,7 @@ extern void _db_unlock_file(void); #define DBUG_IN_USE 0 #define DEBUGGER_OFF #define DEBUGGER_ON +#define DBUG_END() #define DBUG_LOCK_FILE #define DBUG_UNLOCK_FILE #define DBUG_OUTPUT(A) diff --git a/include/my_sys.h b/include/my_sys.h index 65a295ee39e..229389f1ac5 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -75,6 +75,7 @@ extern int NEAR my_errno; /* Last error in mysys */ #define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */ #define MY_GIVE_INFO 2 /* Give time info about process*/ +#define MY_DONT_FREE_DBUG 4 /* Do not call DBUG_END() in my_end() */ #define ME_HIGHBYTE 8 /* Shift for colours */ #define ME_NOCUR 1 /* Don't use curses message */ diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 7713fd8dd4d..c1e0703af10 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -178,7 +178,7 @@ void STDCALL mysql_server_end() /* If library called my_init(), free memory allocated by it */ if (!org_my_init_done) { - my_end(0); + my_end(MY_DONT_FREE_DBUG); #ifndef THREAD /* Remove TRACING, if enabled by mysql_debug() */ DBUG_POP(); diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index e3257ce5fd0..e38e2624e19 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -326,3 +326,20 @@ deallocate prepare s; set @str=NULL; drop table t2; drop table t1; +create table t1 ( +some_id smallint(5) unsigned, +key (some_id) +); +insert into t1 values (1),(2); +select some_id from t1 where some_id not in(2,-1); +some_id +1 +select some_id from t1 where some_id not in(-4,-1,-4); +some_id +1 +2 +select some_id from t1 where some_id not in(-4,-1,3423534,2342342); +some_id +1 +2 +drop table t1; diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index 351d1fc2c92..8ddf1fbe314 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -220,3 +220,15 @@ set @str=NULL; drop table t2; drop table t1; +# BUG#19618: Crash in range optimizer for +# "unsigned_keypart NOT IN(negative_number,...)" +# (introduced in fix BUG#15872) +create table t1 ( + some_id smallint(5) unsigned, + key (some_id) +); +insert into t1 values (1),(2); +select some_id from t1 where some_id not in(2,-1); +select some_id from t1 where some_id not in(-4,-1,-4); +select some_id from t1 where some_id not in(-4,-1,3423534,2342342); +drop table t1; diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index 51a195e3d0e..81f0e8a0af7 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -192,7 +192,7 @@ drop table t1; # #14157: utf8 encoding in binlog without set character_set_client # ---exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `ÑÝÉË` (a int); insert into `ÑÝÉË` values (1); insert into t1 select * from `ÑÝÉË`' +--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=latin1 test -e 'create table t1 (a int); set names latin1; create temporary table `äöüÄÖÜ` (a int); insert into `äöüÄÖÜ` values (1); insert into t1 select * from `äöüÄÖÜ`' sync_slave_with_master; #connection slave; diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 7737810653d..3c2ac1a7ea5 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -11,7 +11,7 @@ fun:calloc fun:_dl_allocate_tls fun:allocate_stack - fun:pthread_create@@GLIBC_2.1 + fun:pthread_create* } { @@ -33,15 +33,6 @@ fun:pthread_create* } -{ - pthread allocate_dtv memory loss second - Memcheck:Leak - fun:calloc - fun:allocate_dtv - fun:_dl_allocate_tls - fun:pthread_create* -} - { pthread memalign memory loss Memcheck:Leak @@ -72,17 +63,6 @@ obj:/lib/ld-*.so } -{ - pthread strstr uninit - Memcheck:Cond - fun:strstr - obj:/lib/tls/libpthread.so.* - obj:/lib/tls/libpthread.so.* - fun:call_init - fun:_dl_init - obj:/lib/ld-*.so -} - { pthread errno Memcheck:Leak @@ -152,3 +132,163 @@ obj:*/libz.so.* fun:gzflush } + +# +# Leaks reported in _dl_* internal functions on Linux amd64 / glibc2.3.2. +# + +{ + _dl_start invalid write8 + Memcheck:Addr8 + fun:_dl_start +} + +{ + _dl_start invalid write4 + Memcheck:Addr4 + fun:_dl_start +} + +{ + _dl_start/_dl_setup_hash invalid read8 + Memcheck:Addr8 + fun:_dl_setup_hash + fun:_dl_start +} + +{ + _dl_sysdep_start invalid write8 + Memcheck:Addr8 + fun:_dl_sysdep_start +} + +{ + _dl_init invalid write8 + Memcheck:Addr8 + fun:_dl_init +} + +{ + _dl_init invalid write4 + Memcheck:Addr4 + fun:_dl_init +} + +{ + _dl_init/_dl_init invalid read8 + Memcheck:Addr8 + fun:_dl_debug_initialize + fun:_dl_init +} + +{ + _dl_init/_dl_debug_state invalid read8 + Memcheck:Addr8 + fun:_dl_debug_state + fun:_dl_init +} + +{ + init invalid write8 + Memcheck:Addr8 + fun:init +} + +{ + fixup invalid write8 + Memcheck:Addr8 + fun:fixup +} + +{ + fixup/_dl_lookup_versioned_symbol invalid read8 + Memcheck:Addr8 + fun:_dl_lookup_versioned_symbol + fun:fixup +} + +{ + _dl_runtime_resolve invalid read8 + Memcheck:Addr8 + fun:_dl_runtime_resolve +} + +{ + __libc_start_main invalid write8 + Memcheck:Addr8 + fun:__libc_start_main +} + +{ + __libc_start_main/__sigjmp_save invalid write4 + Memcheck:Addr4 + fun:__sigjmp_save + fun:__libc_start_main +} + +# +# These seem to be libc threading stuff, not related to MySQL code (allocations +# during pthread_exit()). Googling shows other projects also using these +# suppressions. +# +# Note that these all stem from pthread_exit() deeper in the call stack, but +# Valgrind only allows the top four calls in the suppressions. +# + +{ + libc pthread_exit 1 + Memcheck:Leak + fun:malloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object +} + +{ + libc pthread_exit 2 + Memcheck:Leak + fun:malloc + fun:_dl_map_object + fun:dl_open_worker + fun:_dl_catch_error +} + +{ + libc pthread_exit 3 + Memcheck:Leak + fun:malloc + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error +} + +{ + libc pthread_exit 4 + Memcheck:Leak + fun:calloc + fun:_dl_check_map_versions + fun:dl_open_worker + fun:_dl_catch_error +} + +{ + libc pthread_exit 5 + Memcheck:Leak + fun:calloc + fun:_dl_new_object + fun:_dl_map_object_from_fd + fun:_dl_map_object +} + + + +# +# This is seen internally in the system libraries on 64-bit RHAS3. +# + +{ + __lll_mutex_unlock_wake uninitialized + Memcheck:Param + futex(utime) + fun:__lll_mutex_unlock_wake +} diff --git a/mysys/my_init.c b/mysys/my_init.c index c2bfdde0ddd..9b8d4db172f 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -196,8 +196,10 @@ Voluntary context switches %ld, Involuntary context switches %ld\n", _CrtDumpMemoryLeaks(); #endif } + + if (!(infoflag & MY_DONT_FREE_DBUG)) + DBUG_END(); /* Must be done before my_thread_end */ #ifdef THREAD - DBUG_POP(); /* Must be done before my_thread_end */ my_thread_end(); my_thread_global_end(); #if defined(SAFE_MUTEX) diff --git a/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp index 761f959acdc..f83f21f14d8 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp @@ -1496,6 +1496,7 @@ int Dbtup::interpreterNextLab(Signal* signal, // word read. Thus we set the register to be a 32 bit register. /* ------------------------------------------------------------- */ TregMemBuffer[theRegister] = 0x50; + // arithmetic conversion if big-endian * (Int64*)(TregMemBuffer+theRegister+2) = TregMemBuffer[theRegister+1]; } else if (TnoDataRW == 3) { /* ------------------------------------------------------------- */ @@ -1554,6 +1555,11 @@ int Dbtup::interpreterNextLab(Signal* signal, Tlen = TattrNoOfWords + 1; if (Toptype == ZUPDATE) { if (TattrNoOfWords <= 2) { + if (TattrNoOfWords == 1) { + // arithmetic conversion if big-endian + TdataForUpdate[1] = *(Int64*)&TregMemBuffer[theRegister + 2]; + TdataForUpdate[2] = 0; + } if (TregType == 0) { /* --------------------------------------------------------- */ // Write a NULL value into the attribute diff --git a/ndb/test/ndbapi/Makefile.am b/ndb/test/ndbapi/Makefile.am index 0533493ba09..7dfa239cb66 100644 --- a/ndb/test/ndbapi/Makefile.am +++ b/ndb/test/ndbapi/Makefile.am @@ -24,6 +24,7 @@ testOIBasic \ testOperations \ testRestartGci \ testScan \ +testInterpreter \ testScanInterpreter \ testScanPerf \ testSystemRestart \ @@ -65,6 +66,7 @@ testOIBasic_SOURCES = testOIBasic.cpp testOperations_SOURCES = testOperations.cpp testRestartGci_SOURCES = testRestartGci.cpp testScan_SOURCES = testScan.cpp ScanFunctions.hpp +testInterpreter_SOURCES = testInterpreter.cpp testScanInterpreter_SOURCES = testScanInterpreter.cpp ScanFilter.hpp ScanInterpretTest.hpp testScanPerf_SOURCES = testScanPerf.cpp testSystemRestart_SOURCES = testSystemRestart.cpp diff --git a/ndb/test/ndbapi/testInterpreter.cpp b/ndb/test/ndbapi/testInterpreter.cpp index 0baba33d2b2..5d930d3d555 100644 --- a/ndb/test/ndbapi/testInterpreter.cpp +++ b/ndb/test/ndbapi/testInterpreter.cpp @@ -79,46 +79,46 @@ int runTestIncValue32(NDBT_Context* ctx, NDBT_Step* step){ Ndb* pNdb = GETNDB(step); - NdbConnection* pTrans = pNdb->startTransaction(); - if (pTrans == NULL){ - ERR(pNdb->getNdbError()); - return NDBT_FAILED; - } - - NdbOperation* pOp = pTrans->getNdbOperation(pTab->getName()); - if (pOp == NULL) { - ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); - return NDBT_FAILED; - } - - int check = pOp->interpretedUpdateTuple(); - if( check == -1 ) { - ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); - return NDBT_FAILED; - } - - - // Primary keys - Uint32 pkVal = 1; - check = pOp->equal("KOL1", pkVal ); - if( check == -1 ) { - ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); - return NDBT_FAILED; - } - - // Attributes - - // Update column - Uint32 valToIncWith = 1; - check = pOp->incValue("KOL2", valToIncWith); - if( check == -1 ) { - ERR(pTrans->getNdbError()); - pNdb->closeTransaction(pTrans); - return NDBT_FAILED; - } + NdbConnection* pTrans = pNdb->startTransaction(); + if (pTrans == NULL){ + ERR(pNdb->getNdbError()); + return NDBT_FAILED; + } + + NdbOperation* pOp = pTrans->getNdbOperation(pTab->getName()); + if (pOp == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + int check = pOp->interpretedUpdateTuple(); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + + // Primary keys + Uint32 pkVal = 1; + check = pOp->equal("KOL1", pkVal ); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + // Attributes + + // Update column + Uint32 valToIncWith = 1; + check = pOp->incValue("KOL2", valToIncWith); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } NdbRecAttr* valueRec = pOp->getValue("KOL2"); if( valueRec == NULL ) { @@ -142,6 +142,122 @@ int runTestIncValue32(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_OK; } +int runTestBug19537(NDBT_Context* ctx, NDBT_Step* step){ + int result = NDBT_OK; + const NdbDictionary::Table * pTab = ctx->getTab(); + Ndb* pNdb = GETNDB(step); + + if (strcmp(pTab->getName(), "T1") != 0) { + g_err << "runTestBug19537: skip, table != T1" << endl; + return NDBT_OK; + } + + + NdbConnection* pTrans = pNdb->startTransaction(); + if (pTrans == NULL){ + ERR(pNdb->getNdbError()); + return NDBT_FAILED; + } + + NdbOperation* pOp = pTrans->getNdbOperation(pTab->getName()); + if (pOp == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if (pOp->interpretedUpdateTuple() == -1) { + ERR(pOp->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + + // Primary keys + const Uint32 pkVal = 1; + if (pOp->equal("KOL1", pkVal) == -1) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + // Load 64-bit constant into register 1 and + // write from register 1 to 32-bit column KOL2 + const Uint64 reg_val = 0x0102030405060708ULL; + + const Uint32* reg_ptr32 = (const Uint32*)®_val; + if (reg_ptr32[0] == 0x05060708 && reg_ptr32[1] == 0x01020304) { + g_err << "runTestBug19537: platform is LITTLE endian" << endl; + } else if (reg_ptr32[0] == 0x01020304 && reg_ptr32[1] == 0x05060708) { + g_err << "runTestBug19537: platform is BIG endian" << endl; + } else { + g_err << "runTestBug19537: impossible platform" + << hex << " [0]=" << reg_ptr32[0] << " [1]=" <closeTransaction(pTrans); + return NDBT_FAILED; + } + + if (pOp->load_const_u64(1, reg_val) == -1 || + pOp->write_attr("KOL2", 1) == -1) { + ERR(pOp->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if (pTrans->execute(Commit) == -1) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + // Read value via a new transaction + + pTrans = pNdb->startTransaction(); + if (pTrans == NULL){ + ERR(pNdb->getNdbError()); + return NDBT_FAILED; + } + + pOp = pTrans->getNdbOperation(pTab->getName()); + if (pOp == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + Uint32 kol2 = 0x09090909; + if (pOp->readTuple() == -1 || + pOp->equal("KOL1", pkVal) == -1 || + pOp->getValue("KOL2", (char*)&kol2) == 0) { + ERR(pOp->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if (pTrans->execute(Commit) == -1) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + // Expected conversion as in C - truncate to lower (logical) word + + if (kol2 == 0x01020304) { + g_err << "runTestBug19537: the bug manifests itself !" << endl; + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if (kol2 != 0x05060708) { + g_err << "runTestBug19537: impossible KOL2 " << hex << kol2 << endl; + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + pNdb->closeTransaction(pTrans); + return NDBT_OK; +} + NDBT_TESTSUITE(testInterpreter); TESTCASE("IncValue32", @@ -156,6 +272,12 @@ TESTCASE("IncValue64", INITIALIZER(runTestIncValue64); FINALIZER(runClearTable); } +TESTCASE("Bug19537", + "Test big-endian write_attr of 32 bit integer\n"){ + INITIALIZER(runLoadTable); + INITIALIZER(runTestBug19537); + FINALIZER(runClearTable); +} #if 0 TESTCASE("MaxTransactions", "Start transactions until no more can be created\n"){ diff --git a/sql/item.cc b/sql/item.cc index ba378e56cb0..51a2f9a24f3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5365,7 +5365,7 @@ bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const } -void Item_trigger_field::set_required_privilege(const bool rw) +void Item_trigger_field::set_required_privilege(bool rw) { /* Require SELECT and UPDATE privilege if this field will be read and diff --git a/sql/item.h b/sql/item.h index cfc2306f15d..19a57a10720 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2187,7 +2187,7 @@ public: void cleanup(); private: - void set_required_privilege(const bool rw); + void set_required_privilege(bool rw); bool set_value(THD *thd, sp_rcontext *ctx, Item **it); public: diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ef2f52a33df..004b1761c77 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -986,6 +986,10 @@ static void __cdecl kill_server(int sig_ptr) pthread_join(select_thread, NULL); // wait for main thread #endif /* __NETWARE__ */ +#if defined(__NETWARE__) || (defined(USE_ONE_SIGNAL_HAND) && !defined(__WIN__) && !defined(OS2)) + my_thread_end(); +#endif + pthread_exit(0); /* purecov: deadcode */ #endif /* EMBEDDED_LIBRARY */ diff --git a/sql/opt_range.cc b/sql/opt_range.cc index fb4af4e7932..e36932cbc0c 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3503,17 +3503,46 @@ static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func, if (inv) { - /* - We get here for conditions like "t.keypart NOT IN (....)". - - If the IN-list contains only constants (and func->array is an ordered - array of them), we construct the appropriate SEL_ARG tree manually, - because constructing it using the range analyzer (as - AND_i( t.keypart != c_i)) will cause lots of memory to be consumed - (see BUG#15872). - */ if (func->array && func->cmp_type != ROW_RESULT) { + /* + We get here for conditions in form "t.key NOT IN (c1, c2, ...)" + (where c{i} are constants). + Our goal is to produce a SEL_ARG graph that represents intervals: + + ($MINmem_root; + param->thd->mem_root= param->old_root; /* Create one Item_type constant object. We'll need it as get_mm_parts only accepts constant values wrapped in Item_Type @@ -3522,25 +3551,35 @@ static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func, per-statement mem_root (while thd->mem_root is currently pointing to mem_root local to range optimizer). */ - MEM_ROOT *tmp_root= param->mem_root; - param->thd->mem_root= param->old_root; Item *value_item= func->array->create_item(); param->thd->mem_root= tmp_root; if (!value_item) break; - /* Get a SEL_TREE for "-inf < X < c_0" interval */ - func->array->value_to_item(0, value_item); - tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, - value_item, cmp_type); - if (!tree) + /* Get a SEL_TREE for "(-inf|NULL) < X < c_0" interval. */ + uint i=0; + do + { + func->array->value_to_item(i, value_item); + tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, + value_item, cmp_type); + if (!tree) + break; + i++; + } while (i < func->array->count && tree->type == SEL_TREE::IMPOSSIBLE); + + if (!tree || tree->type == SEL_TREE::IMPOSSIBLE) + { + /* We get here in cases like "t.unsigned NOT IN (-1,-2,-3) */ + tree= NULL; break; + } #define NOT_IN_IGNORE_THRESHOLD 1000 SEL_TREE *tree2; if (func->array->count < NOT_IN_IGNORE_THRESHOLD) { - for (uint i=1; i < func->array->count; i++) + for (; i < func->array->count; i++) { if (func->array->compare_elems(i, i-1)) { @@ -3548,32 +3587,44 @@ static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func, func->array->value_to_item(i, value_item); tree2= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC, value_item, cmp_type); - + if (!tree2) + { + tree= NULL; + break; + } + /* Change all intervals to be "c_{i-1} < X < c_i" */ for (uint idx= 0; idx < param->keys; idx++) { - SEL_ARG *new_interval; - if ((new_interval= tree2->keys[idx])) + SEL_ARG *new_interval, *last_val; + if (((new_interval= tree2->keys[idx])) && + ((last_val= tree->keys[idx]->last()))) { - SEL_ARG *last_val= tree->keys[idx]->last(); new_interval->min_value= last_val->max_value; new_interval->min_flag= NEAR_MIN; } } + /* + The following doesn't try to allocate memory so no need to + check for NULL. + */ tree= tree_or(param, tree, tree2); } } } else func->array->value_to_item(func->array->count - 1, value_item); - - /* - Get the SEL_TREE for the last "c_last < X < +inf" interval - (value_item cotains c_last already) - */ - tree2= get_mm_parts(param, cond_func, field, Item_func::GT_FUNC, - value_item, cmp_type); - tree= tree_or(param, tree, tree2); + + if (tree && tree->type != SEL_TREE::IMPOSSIBLE) + { + /* + Get the SEL_TREE for the last "c_last < X < +inf" interval + (value_item cotains c_last already) + */ + tree2= get_mm_parts(param, cond_func, field, Item_func::GT_FUNC, + value_item, cmp_type); + tree= tree_or(param, tree, tree2); + } } else { diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5b40f93f002..02b2f88676f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -6023,20 +6023,21 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, } /* table privileges */ + rw_rdlock(&LOCK_grant); if (grant->version != grant_version) { - rw_rdlock(&LOCK_grant); grant->grant_table= table_hash_search(sctx->host, sctx->ip, db, sctx->priv_user, table, 0); /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */ - rw_unlock(&LOCK_grant); } if (grant->grant_table != 0) { grant->privilege|= grant->grant_table->privs; } + rw_unlock(&LOCK_grant); + DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege)); DBUG_VOID_RETURN; }