From 818b3a91231119663a95b854ab1e0e2d7a2d3feb Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Wed, 4 May 2016 14:06:45 +0530 Subject: Bug#12818255: READ-ONLY OPTION DOES NOT ALLOW INSERTS/UPDATES ON TEMPORARY TABLES Bug#14294223: CHANGES NOT ALLOWED TO TEMPORARY TABLES ON READ-ONLY SERVERS Problem: ======== Running 5.5.14 in read only we can create temporary tables but can not insert or update records in the table. When we try we get Error 1290 : The MySQL server is running with the --read-only option so it cannot execute this statement. Analysis: ========= This bug is very specific to binlog being enabled and binlog-format being stmt/mixed. Standalone server without binlog enabled or with row based binlog-mode works fine. How standalone server and row based replication work: ===================================================== Standalone server and row based replication mark the transactions as read_write only when they are modifying non temporary tables as part of their current transaction. Because of this when code enters commit phase it checks if a transaction is read_write or not. If the transaction is read_write and global read only mode is enabled those transaction will fail with 'server is read only mode' error. In the case of statement based mode at the time of writing to binary log a binlog handler is created and it is always marked as read_write. In case of temporary tables even though the engine did not mark the transaction as read_write but the new transaction that is started by binlog handler is considered as read_write. Hence in this case when code enters commit phase it finds one handler which has a read_write transaction even when we are modifying temporary table. This causes the server to throw an error when global read-only mode is enabled. Fix: ==== At the time of commit in "ha_commit_trans" if a read_write transaction is found, we should check if this transaction is coming from a handler other than binlog_handler. This will ensure that there is a genuine read_write transaction being sent by the engine apart from binlog_handler and only then it should be blocked. --- sql/handler.cc | 2 +- sql/log.cc | 8 +++----- sql/log.h | 2 +- sql/log_event.cc | 3 ++- 4 files changed, 7 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 9d57cba73dc..79cf7ac2fd9 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1279,7 +1279,7 @@ int ha_commit_trans(THD *thd, bool all) DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock"); } - if (rw_trans && + if (rw_trans && stmt_has_updated_trans_table(ha_info) && opt_readonly && !(thd->security_ctx->master_access & SUPER_ACL) && !thd->slave_thread) diff --git a/sql/log.cc b/sql/log.cc index a7f05905514..e0ba93b0959 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4562,17 +4562,15 @@ trans_has_updated_trans_table(const THD* thd) This function checks if a transactional table was updated by the current statement. - @param thd The client thread that executed the current statement. + @param ha_list Registered storage engine handler list. @return @c true if a transactional table was updated, @c false otherwise. */ bool -stmt_has_updated_trans_table(const THD *thd) +stmt_has_updated_trans_table(Ha_trx_info* ha_list) { Ha_trx_info *ha_info; - - for (ha_info= thd->transaction.stmt.ha_list; ha_info; - ha_info= ha_info->next()) + for (ha_info= ha_list; ha_info; ha_info= ha_info->next()) { if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton) return (TRUE); diff --git a/sql/log.h b/sql/log.h index 7d1c3161ac2..dd09cb41026 100644 --- a/sql/log.h +++ b/sql/log.h @@ -25,7 +25,7 @@ class Master_info; class Format_description_log_event; bool trans_has_updated_trans_table(const THD* thd); -bool stmt_has_updated_trans_table(const THD *thd); +bool stmt_has_updated_trans_table(Ha_trx_info* ha_list); bool use_trans_cache(const THD* thd, bool is_transactional); bool ending_trans(THD* thd, const bool all); bool ending_single_stmt_trans(THD* thd, const bool all); diff --git a/sql/log_event.cc b/sql/log_event.cc index 702cf1d575a..5dbeb1eb4b9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2637,7 +2637,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, { cache_type= Log_event::EVENT_NO_CACHE; } - else if (using_trans || trx_cache || stmt_has_updated_trans_table(thd) || + else if (using_trans || trx_cache || + stmt_has_updated_trans_table(thd->transaction.stmt.ha_list) || thd->lex->is_mixed_stmt_unsafe(thd->in_multi_stmt_transaction_mode(), thd->variables.binlog_direct_non_trans_update, trans_has_updated_trans_table(thd), -- cgit v1.2.1 From df7ecf64f5b9c6fb4b7789a414306de89b58bec7 Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Fri, 13 May 2016 16:42:45 +0530 Subject: Bug#23251517: SEMISYNC REPLICATION HANGING Revert following bug fix: Bug#20685029: SLAVE IO THREAD SHOULD STOP WHEN DISK IS FULL Bug#21753696: MAKE SHOW SLAVE STATUS NON BLOCKING IF IO THREAD WAITS FOR DISK SPACE This fix results in a deadlock between slave IO thread and SQL thread. --- sql/log.cc | 75 ++++--------------------------------------------------- sql/log.h | 5 ++-- sql/slave.cc | 38 +++++++++------------------- sql/slave.h | 2 +- sql/sql_reload.cc | 2 +- 5 files changed, 21 insertions(+), 101 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index e0ba93b0959..50d7762af6d 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -37,7 +37,6 @@ #include "log_event.h" // Query_log_event #include "rpl_filter.h" #include "rpl_rli.h" -#include "rpl_mi.h" #include "sql_audit.h" #include "sql_show.h" @@ -4378,22 +4377,13 @@ end: } -#ifdef HAVE_REPLICATION -bool MYSQL_BIN_LOG::append(Log_event* ev, Master_info *mi) +bool MYSQL_BIN_LOG::append(Log_event* ev) { bool error = 0; - mysql_mutex_assert_owner(&mi->data_lock); mysql_mutex_lock(&LOCK_log); DBUG_ENTER("MYSQL_BIN_LOG::append"); DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); - /* - Release data_lock by holding LOCK_log, while writing into the relay log. - If slave IO thread waits here for free space, we don't want - SHOW SLAVE STATUS to hang on mi->data_lock. Note LOCK_log mutex is - sufficient to block SQL thread when IO thread is updating relay log here. - */ - mysql_mutex_unlock(&mi->data_lock); /* Log_event::write() is smart enough to use my_b_write() or my_b_append() depending on the kind of cache we have. @@ -4408,58 +4398,24 @@ bool MYSQL_BIN_LOG::append(Log_event* ev, Master_info *mi) if (flush_and_sync(0)) goto err; if ((uint) my_b_append_tell(&log_file) > max_size) - { - /* - If rotation is required we must acquire data_lock to protect - description_event from clients executing FLUSH LOGS in parallel. - In order do that we must release the existing LOCK_log so that we - get it once again in proper locking order to avoid dead locks. - i.e data_lock , LOCK_log. - */ - mysql_mutex_unlock(&LOCK_log); - mysql_mutex_lock(&mi->data_lock); - mysql_mutex_lock(&LOCK_log); error= new_file_without_locking(); - /* - After rotation release data_lock, we need the LOCK_log till we signal - the updation. - */ - mysql_mutex_unlock(&mi->data_lock); - } err: - signal_update(); // Safe as we don't call close mysql_mutex_unlock(&LOCK_log); - mysql_mutex_lock(&mi->data_lock); + signal_update(); // Safe as we don't call close DBUG_RETURN(error); } -bool MYSQL_BIN_LOG::appendv(Master_info* mi, const char* buf, uint len,...) +bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...) { bool error= 0; DBUG_ENTER("MYSQL_BIN_LOG::appendv"); va_list(args); va_start(args,len); - mysql_mutex_assert_owner(&mi->data_lock); - mysql_mutex_lock(&LOCK_log); DBUG_ASSERT(log_file.type == SEQ_READ_APPEND); - /* - Release data_lock by holding LOCK_log, while writing into the relay log. - If slave IO thread waits here for free space, we don't want - SHOW SLAVE STATUS to hang on mi->data_lock. Note LOCK_log mutex is - sufficient to block SQL thread when IO thread is updating relay log here. - */ - mysql_mutex_unlock(&mi->data_lock); - DBUG_EXECUTE_IF("simulate_io_thd_wait_for_disk_space", - { - const char act[]= "disk_full_reached SIGNAL parked"; - DBUG_ASSERT(opt_debug_sync_timeout > 0); - DBUG_ASSERT(!debug_sync_set_action(current_thd, - STRING_WITH_LEN(act))); - };); - + mysql_mutex_assert_owner(&LOCK_log); do { if (my_b_append(&log_file,(uchar*) buf,len)) @@ -4472,34 +4428,13 @@ bool MYSQL_BIN_LOG::appendv(Master_info* mi, const char* buf, uint len,...) DBUG_PRINT("info",("max_size: %lu",max_size)); if (flush_and_sync(0)) goto err; - if ((uint) my_b_append_tell(&log_file) > - DBUG_EVALUATE_IF("rotate_slave_debug_group", 500, max_size)) - { - /* - If rotation is required we must acquire data_lock to protect - description_event from clients executing FLUSH LOGS in parallel. - In order do that we must release the existing LOCK_log so that we - get it once again in proper locking order to avoid dead locks. - i.e data_lock , LOCK_log. - */ - mysql_mutex_unlock(&LOCK_log); - mysql_mutex_lock(&mi->data_lock); - mysql_mutex_lock(&LOCK_log); + if ((uint) my_b_append_tell(&log_file) > max_size) error= new_file_without_locking(); - /* - After rotation release data_lock, we need the LOCK_log till we signal - the updation. - */ - mysql_mutex_unlock(&mi->data_lock); - } err: if (!error) signal_update(); - mysql_mutex_unlock(&LOCK_log); - mysql_mutex_lock(&mi->data_lock); DBUG_RETURN(error); } -#endif bool MYSQL_BIN_LOG::flush_and_sync(bool *synced) { diff --git a/sql/log.h b/sql/log.h index dd09cb41026..b5e751386a6 100644 --- a/sql/log.h +++ b/sql/log.h @@ -20,7 +20,6 @@ #include "handler.h" /* my_xid */ class Relay_log_info; -class Master_info; class Format_description_log_event; @@ -455,8 +454,8 @@ public: v stands for vector invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0) */ - bool appendv(Master_info* mi, const char* buf,uint len,...); - bool append(Log_event* ev, Master_info* mi); + bool appendv(const char* buf,uint len,...); + bool append(Log_event* ev); void make_log_name(char* buf, const char* log_ident); bool is_active(const char* log_file_name); diff --git a/sql/slave.cc b/sql/slave.cc index 31037c453d3..acf68e231f3 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1660,7 +1660,7 @@ Waiting for the slave SQL thread to free enough relay log space"); #endif if (rli->sql_force_rotate_relay) { - rotate_relay_log(rli->mi, true/*need_data_lock=true*/); + rotate_relay_log(rli->mi); rli->sql_force_rotate_relay= false; } @@ -1705,7 +1705,7 @@ static void write_ignored_events_info_to_relay_log(THD *thd, Master_info *mi) if (likely((bool)ev)) { ev->server_id= 0; // don't be ignored by slave SQL thread - if (unlikely(rli->relay_log.append(ev, mi))) + if (unlikely(rli->relay_log.append(ev))) mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), "failed to write a Rotate event" @@ -3605,7 +3605,7 @@ static int process_io_create_file(Master_info* mi, Create_file_log_event* cev) break; Execute_load_log_event xev(thd,0,0); xev.log_pos = cev->log_pos; - if (unlikely(mi->rli.relay_log.append(&xev, mi))) + if (unlikely(mi->rli.relay_log.append(&xev))) { mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), @@ -3619,7 +3619,7 @@ static int process_io_create_file(Master_info* mi, Create_file_log_event* cev) { cev->block = net->read_pos; cev->block_len = num_bytes; - if (unlikely(mi->rli.relay_log.append(cev, mi))) + if (unlikely(mi->rli.relay_log.append(cev))) { mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), @@ -3634,7 +3634,7 @@ static int process_io_create_file(Master_info* mi, Create_file_log_event* cev) aev.block = net->read_pos; aev.block_len = num_bytes; aev.log_pos = cev->log_pos; - if (unlikely(mi->rli.relay_log.append(&aev, mi))) + if (unlikely(mi->rli.relay_log.append(&aev))) { mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE, ER(ER_SLAVE_RELAY_LOG_WRITE_FAILURE), @@ -3713,7 +3713,7 @@ static int process_io_rotate(Master_info *mi, Rotate_log_event *rev) Rotate the relay log makes binlog format detection easier (at next slave start or mysqlbinlog) */ - DBUG_RETURN(rotate_relay_log(mi, false/*need_data_lock=false*/)); + DBUG_RETURN(rotate_relay_log(mi) /* will take the right mutexes */); } /* @@ -3819,7 +3819,7 @@ static int queue_binlog_ver_1_event(Master_info *mi, const char *buf, Log_event::Log_event(const char* buf...) in log_event.cc). */ ev->log_pos+= event_len; /* make log_pos be the pos of the end of the event */ - if (unlikely(rli->relay_log.append(ev, mi))) + if (unlikely(rli->relay_log.append(ev))) { delete ev; mysql_mutex_unlock(&mi->data_lock); @@ -3875,7 +3875,7 @@ static int queue_binlog_ver_3_event(Master_info *mi, const char *buf, inc_pos= event_len; break; } - if (unlikely(rli->relay_log.append(ev, mi))) + if (unlikely(rli->relay_log.append(ev))) { delete ev; mysql_mutex_unlock(&mi->data_lock); @@ -4083,6 +4083,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) direct master (an unsupported, useless setup!). */ + mysql_mutex_lock(log_lock); s_id= uint4korr(buf + SERVER_ID_OFFSET); if ((s_id == ::server_id && !mi->rli.replicate_same_server_id) || /* @@ -4115,7 +4116,6 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) IGNORE_SERVER_IDS it increments mi->master_log_pos as well as rli->group_relay_log_pos. */ - mysql_mutex_lock(log_lock); if (!(s_id == ::server_id && !mi->rli.replicate_same_server_id) || (buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT && buf[EVENT_TYPE_OFFSET] != ROTATE_EVENT && @@ -4127,14 +4127,13 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) rli->ign_master_log_pos_end= mi->master_log_pos; } rli->relay_log.signal_update(); // the slave SQL thread needs to re-check - mysql_mutex_unlock(log_lock); DBUG_PRINT("info", ("master_log_pos: %lu, event originating from %u server, ignored", (ulong) mi->master_log_pos, uint4korr(buf + SERVER_ID_OFFSET))); } else { /* write the event to the relay log */ - if (likely(!(rli->relay_log.appendv(mi, buf,event_len,0)))) + if (likely(!(rli->relay_log.appendv(buf,event_len,0)))) { mi->master_log_pos+= inc_pos; DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); @@ -4144,10 +4143,9 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len) { error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE; } - mysql_mutex_lock(log_lock); rli->ign_master_log_name_end[0]= 0; // last event is not ignored - mysql_mutex_unlock(log_lock); } + mysql_mutex_unlock(log_lock); skip_relay_logging: @@ -5007,21 +5005,11 @@ err: locks; here we don't, so this function is mainly taking locks). Returns nothing as we cannot catch any error (MYSQL_BIN_LOG::new_file() is void). - - @param mi Master_info for the IO thread. - @param need_data_lock If true, mi->data_lock will be acquired otherwise, - mi->data_lock must be held by the caller. */ -int rotate_relay_log(Master_info* mi, bool need_data_lock) +int rotate_relay_log(Master_info* mi) { DBUG_ENTER("rotate_relay_log"); - if (need_data_lock) - mysql_mutex_lock(&mi->data_lock); - else - { - mysql_mutex_assert_owner(&mi->data_lock); - } Relay_log_info* rli= &mi->rli; int error= 0; @@ -5056,8 +5044,6 @@ int rotate_relay_log(Master_info* mi, bool need_data_lock) */ rli->relay_log.harvest_bytes_written(&rli->log_space_total); end: - if (need_data_lock) - mysql_mutex_unlock(&mi->data_lock); DBUG_RETURN(error); } diff --git a/sql/slave.h b/sql/slave.h index 0cf8adb0315..7bf136694cc 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -205,7 +205,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, const char** errmsg); void set_slave_thread_options(THD* thd); void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli); -int rotate_relay_log(Master_info* mi, bool need_data_lock); +int rotate_relay_log(Master_info* mi); int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli); pthread_handler_t handle_slave_io(void *arg); diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index f24f31b6399..b29cc9a9433 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -157,7 +157,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long options, { #ifdef HAVE_REPLICATION mysql_mutex_lock(&LOCK_active_mi); - if (rotate_relay_log(active_mi, true/*need_data_lock=true*/)) + if (rotate_relay_log(active_mi)) *write_to_binlog= -1; mysql_mutex_unlock(&LOCK_active_mi); #endif -- cgit v1.2.1 From 90b9c957ba6380a717aaef6285b3f1498f4a29dc Mon Sep 17 00:00:00 2001 From: Karthik Kamath Date: Wed, 18 May 2016 11:07:29 +0530 Subject: BUG#21142859: FUNCTION UPDATING A VIEW FAILS TO FIND TABLE THAT ACTUALLY EXISTS ANALYSIS: ========= Stored functions updating a view where the view table has a trigger defined that updates another table, fails reporting an error that the table doesn't exist. If there is a trigger defined on a table, a variable 'trg_event_map' will be set to a non-zero value after the parsed tree creation. This indicates what triggers we need to pre-load for the TABLE_LIST when opening an associated table. During the prelocking phase, the variable 'trg_event_map' will not be set for the view table. This value will be set after the processing of triggers defined on the table. During the processing of sub-statements, 'locked_tables_mode' will be set to 'LTM_PRELOCKED' which denotes that further locking of tables/functions cannot be done. This results in the other table not being locked and thus further processing results in an error getting reported. FIX: ==== During the prelocking of view, the value of 'trg_event_map' of the view is copied to 'trg_event_map' of the next table in the TABLE_LIST. This results in the locking of tables associated with the trigger as well. --- sql/sql_base.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f559974c86b..27dcbee7b8f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -5211,6 +5211,15 @@ handle_view(THD *thd, Query_tables_list *prelocking_ctx, &table_list->view->sroutines_list, table_list->top_table()); } + + /* + If a trigger was defined on one of the associated tables then assign the + 'trg_event_map' value of the view to the next table in table_list. When a + Stored function is invoked, all the associated tables including the tables + associated with the trigger are prelocked. + */ + if (table_list->trg_event_map && table_list->next_global) + table_list->next_global->trg_event_map= table_list->trg_event_map; return FALSE; } -- cgit v1.2.1 From 115f08284df1dac6a29cbca49dc7534b4a4f23f7 Mon Sep 17 00:00:00 2001 From: Sreeharsha Ramanavarapu Date: Tue, 24 May 2016 07:44:21 +0530 Subject: Bug #23279858: MYSQLD GOT SIGNAL 11 ON SIMPLE SELECT NAME_CONST QUERY ISSUE: ------ Using NAME_CONST with a non-constant negated expression as value can result in incorrect behavior. SOLUTION: --------- The problem can be avoided by checking whether the argument is a constant value. The fix is a backport of Bug#12735545. --- sql/item.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index f4917448dda..1541314ec97 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1358,6 +1358,11 @@ bool Item_name_const::is_null() Item_name_const::Item_name_const(Item *name_arg, Item *val): value_item(val), name_item(name_arg) { + /* + The value argument to NAME_CONST can only be a literal constant. Some extra + tests are needed to support a collation specificer and to handle negative + values. + */ if (!(valid_args= name_item->basic_const_item() && (value_item->basic_const_item() || ((value_item->type() == FUNC_ITEM) && @@ -1365,8 +1370,8 @@ Item_name_const::Item_name_const(Item *name_arg, Item *val): Item_func::COLLATE_FUNC) || ((((Item_func *) value_item)->functype() == Item_func::NEG_FUNC) && - (((Item_func *) value_item)->key_item()->type() != - FUNC_ITEM))))))) + (((Item_func *) + value_item)->key_item()->basic_const_item()))))))) my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST"); Item::maybe_null= TRUE; } -- cgit v1.2.1 From 9f7288e2e0179db478d20c74f57b5c7d6c95f793 Mon Sep 17 00:00:00 2001 From: Thayumanavar S Date: Mon, 20 Jun 2016 11:35:43 +0530 Subject: BUG#23080148 - BACKPORT BUG 14653594 AND BUG 20683959 TO MYSQL-5.5 The bug asks for a backport of bug#1463594 and bug#20682959. This is required because of the fact that if replication is enabled, master transaction can commit whereas slave can't commit due to not exact 'enviroment'. This manifestation is seen in bug#22024200. --- sql/sql_load.cc | 77 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 28 deletions(-) (limited to 'sql') diff --git a/sql/sql_load.cc b/sql/sql_load.cc index c084e5e3839..a46967a24a8 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -1363,8 +1363,8 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs, set_if_bigger(length,line_start.length()); stack=stack_pos=(int*) sql_alloc(sizeof(int)*length); - if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0)))) - error=1; /* purecov: inspected */ + if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(MY_WME)))) + error= true; /* purecov: inspected */ else { end_of_buff=buffer+buff_length; @@ -1556,37 +1556,50 @@ int READ_INFO::read_field() } } #ifdef USE_MB - if (my_mbcharlen(read_charset, chr) > 1 && - to + my_mbcharlen(read_charset, chr) <= end_of_buff) - { - uchar* p= to; - int ml, i; - *to++ = chr; - - ml= my_mbcharlen(read_charset, chr); + uint ml= my_mbcharlen(read_charset, chr); + if (ml == 0) + { + *to= '\0'; + my_error(ER_INVALID_CHARACTER_STRING, MYF(0), + read_charset->csname, buffer); + error= true; + return 1; + } - for (i= 1; i < ml; i++) + if (ml > 1 && + to + ml <= end_of_buff) { - chr= GET; - if (chr == my_b_EOF) + uchar* p= to; + *to++ = chr; + + for (uint i= 1; i < ml; i++) { - /* - Need to back up the bytes already ready from illformed - multi-byte char - */ - to-= i; - goto found_eof; + chr= GET; + if (chr == my_b_EOF) + { + /* + Need to back up the bytes already ready from illformed + multi-byte char + */ + to-= i; + goto found_eof; + } + *to++ = chr; } - *to++ = chr; - } - if (my_ismbchar(read_charset, + if (my_ismbchar(read_charset, (const char *)p, (const char *)to)) - continue; - for (i= 0; i < ml; i++) - PUSH(*--to); - chr= GET; - } + continue; + for (uint i= 0; i < ml; i++) + PUSH(*--to); + chr= GET; + } + else if (ml > 1) + { + // Buffer is too small, exit while loop, and reallocate. + PUSH(chr); + break; + } #endif *to++ = (uchar) chr; } @@ -1830,7 +1843,15 @@ int READ_INFO::read_value(int delim, String *val) for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF;) { #ifdef USE_MB - if (my_mbcharlen(read_charset, chr) > 1) + uint ml= my_mbcharlen(read_charset, chr); + if (ml == 0) + { + chr= my_b_EOF; + val->length(0); + return chr; + } + + if (ml > 1) { DBUG_PRINT("read_xml",("multi byte")); int i, ml= my_mbcharlen(read_charset, chr); -- cgit v1.2.1 From 15ef38d2ea97575c71b83db6669ee20000c23a6b Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 27 Jul 2016 00:38:51 +0300 Subject: MDEV-10228: Delete missing rows with OR conditions Fix get_quick_keys(): When building range tree from a condition in form keypart1=const AND (keypart2 < 0 OR keypart2>=0) the SEL_ARG for keypart2 represents an interval (-inf, +inf). However, the logic that sets UNIQUE_RANGE flag fails to recognize this, and sets UNIQUE_RANGE flag if (keypart1, keypart2) covered a unique key. As a result, range access executor assumes the interval can have at most one row and only reads the first row from it. --- sql/opt_range.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index f4ac47fee96..a40363ff9ab 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -10409,8 +10409,10 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, KEY *table_key=quick->head->key_info+quick->index; flag=EQ_RANGE; if ((table_key->flags & HA_NOSAME) && + min_part == key_tree->part && key_tree->part == table_key->key_parts-1) { + DBUG_ASSERT(min_part == max_part); if ((table_key->flags & HA_NULL_PART_KEY) && null_part_in_key(key, param->min_key, -- cgit v1.2.1 From 5fdb3cfcd432b85dc305a1a61c2d018a798a6ac3 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Fri, 29 Jul 2016 18:21:08 +0200 Subject: MDEV-10419: crash in mariadb 10.1.16-MariaDB-1~trusty Fixed initialization and usage of THD reference in subselect engines. --- sql/item_subselect.cc | 8 +++++--- sql/item_subselect.h | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 690318c610a..3727711a395 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -3308,7 +3308,7 @@ int subselect_uniquesubquery_engine::scan_table() } table->file->extra_opt(HA_EXTRA_CACHE, - current_thd->variables.read_buff_size); + get_thd()->variables.read_buff_size); table->null_row= 0; for (;;) { @@ -3746,7 +3746,7 @@ table_map subselect_union_engine::upper_select_const_tables() void subselect_single_select_engine::print(String *str, enum_query_type query_type) { - select_lex->print(thd, str, query_type); + select_lex->print(get_thd(), str, query_type); } @@ -4276,6 +4276,7 @@ bitmap_init_memroot(MY_BITMAP *map, uint n_bits, MEM_ROOT *mem_root) bool subselect_hash_sj_engine::init(List *tmp_columns, uint subquery_id) { + THD *thd= get_thd(); select_union *result_sink; /* Options to create_tmp_table. */ ulonglong tmp_create_options= thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS; @@ -5500,6 +5501,7 @@ bool subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, MY_BITMAP *partial_match_key_parts) { + THD *thd= get_thd(); /* The length in bytes of the rowids (positions) of tmp_table. */ uint rowid_length= tmp_table->file->ref_length; ha_rows row_count= tmp_table->file->stats.records; @@ -6038,7 +6040,7 @@ bool subselect_table_scan_engine::partial_match() } tmp_table->file->extra_opt(HA_EXTRA_CACHE, - current_thd->variables.read_buff_size); + get_thd()->variables.read_buff_size); for (;;) { error= tmp_table->file->ha_rnd_next(tmp_table->record[0]); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 0abfe0d5abc..a44503b4471 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -716,7 +716,8 @@ public: ROWID_MERGE_ENGINE, TABLE_SCAN_ENGINE}; subselect_engine(Item_subselect *si, - select_result_interceptor *res) + select_result_interceptor *res): + thd(NULL) { result= res; item= si; @@ -732,7 +733,7 @@ public: Should be called before prepare(). */ void set_thd(THD *thd_arg); - THD * get_thd() { return thd; } + THD * get_thd() { return thd ? thd : current_thd; } virtual int prepare(THD *)= 0; virtual void fix_length_and_dec(Item_cache** row)= 0; /* -- cgit v1.2.1 From 6b71a6d2d935d997f43a658d45d1e518620cf0ad Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 2 Aug 2016 18:52:51 +0200 Subject: MDEV-10383 Named pipes : multiple servers can listen on the same pipename Use FILE_FLAG_FIRST_PIPE_INSTANCE with the first CreateNamedPipe() call to make sure the pipe does not already exist. --- sql/mysqld.cc | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3450447ceb9..9b8f964629d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2316,26 +2316,17 @@ static void network_init(void) saPipeSecurity.lpSecurityDescriptor = &sdPipeDescriptor; saPipeSecurity.bInheritHandle = FALSE; if ((hPipe= CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE | - PIPE_READMODE_BYTE | - PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - (int) global_system_variables.net_buffer_length, - (int) global_system_variables.net_buffer_length, - NMPWAIT_USE_DEFAULT_WAIT, - &saPipeSecurity)) == INVALID_HANDLE_VALUE) - { - LPVOID lpMsgBuf; - int error=GetLastError(); - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &lpMsgBuf, 0, NULL ); - sql_perror((char *)lpMsgBuf); - LocalFree(lpMsgBuf); - unireg_abort(1); - } + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + (int) global_system_variables.net_buffer_length, + (int) global_system_variables.net_buffer_length, + NMPWAIT_USE_DEFAULT_WAIT, + &saPipeSecurity)) == INVALID_HANDLE_VALUE) + { + sql_perror("Create named pipe failed"); + unireg_abort(1); + } } #endif -- cgit v1.2.1 From ecb7ce7844237e2366ab5e8d9963f370cb1042aa Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 3 Aug 2016 15:55:48 +0400 Subject: MDEV-10467 Assertion `nr >= 0.0' failed in Item_sum_std::val_real() Backporting MDEV-5781 from 10.0. --- sql/item_func.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 4b5f96cd3e7..6c80c7d3d86 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2661,6 +2661,9 @@ double my_double_round(double value, longlong dec, bool dec_unsigned, volatile double value_div_tmp= value / tmp; volatile double value_mul_tmp= value * tmp; + if (!dec_negative && my_isinf(tmp)) // "dec" is too large positive number + return value; + if (dec_negative && my_isinf(tmp)) tmp2= 0.0; else if (!dec_negative && my_isinf(value_mul_tmp)) -- cgit v1.2.1 From 511313b9d640b8e4b2860980e79889f125d3cd5e Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 3 Aug 2016 13:42:46 +0000 Subject: MDEV-10010 - potential deadlock on windows due to recursive SRWLock acquisition Backport patch from 10.1 --- sql/sql_plugin.cc | 126 ++++++++++++++++++++++++++++-------------------------- sql/sql_plugin.h | 2 + sql/sql_show.cc | 19 ++++++-- 3 files changed, 82 insertions(+), 65 deletions(-) (limited to 'sql') diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index dbbc2622866..c8c8c8ba324 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -2896,68 +2896,8 @@ static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock) if (!thd->variables.dynamic_variables_ptr || (uint)offset > thd->variables.dynamic_variables_head) { - uint idx; - mysql_rwlock_rdlock(&LOCK_system_variables_hash); - - thd->variables.dynamic_variables_ptr= (char*) - my_realloc(thd->variables.dynamic_variables_ptr, - global_variables_dynamic_size, - MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); - - if (global_lock) - mysql_mutex_lock(&LOCK_global_system_variables); - - mysql_mutex_assert_owner(&LOCK_global_system_variables); - - memcpy(thd->variables.dynamic_variables_ptr + - thd->variables.dynamic_variables_size, - global_system_variables.dynamic_variables_ptr + - thd->variables.dynamic_variables_size, - global_system_variables.dynamic_variables_size - - thd->variables.dynamic_variables_size); - - /* - now we need to iterate through any newly copied 'defaults' - and if it is a string type with MEMALLOC flag, we need to strdup - */ - for (idx= 0; idx < bookmark_hash.records; idx++) - { - sys_var_pluginvar *pi; - sys_var *var; - st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx); - - if (v->version <= thd->variables.dynamic_variables_version) - continue; /* already in thd->variables */ - - if (!(var= intern_find_sys_var(v->key + 1, v->name_len)) || - !(pi= var->cast_pluginvar()) || - v->key[0] != plugin_var_bookmark_key(pi->plugin_var->flags)) - continue; - - /* Here we do anything special that may be required of the data types */ - - if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && - pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC) - { - char **pp= (char**) (thd->variables.dynamic_variables_ptr + - *(int*)(pi->plugin_var + 1)); - if ((*pp= *(char**) (global_system_variables.dynamic_variables_ptr + - *(int*)(pi->plugin_var + 1)))) - *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE)); - } - } - - if (global_lock) - mysql_mutex_unlock(&LOCK_global_system_variables); - - thd->variables.dynamic_variables_version= - global_system_variables.dynamic_variables_version; - thd->variables.dynamic_variables_head= - global_system_variables.dynamic_variables_head; - thd->variables.dynamic_variables_size= - global_system_variables.dynamic_variables_size; - + sync_dynamic_session_variables(thd, global_lock); mysql_rwlock_unlock(&LOCK_system_variables_hash); } DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset); @@ -3037,6 +2977,70 @@ void plugin_thdvar_init(THD *thd) } + +void sync_dynamic_session_variables(THD* thd, bool global_lock) +{ + uint idx; + + thd->variables.dynamic_variables_ptr= (char*) + my_realloc(thd->variables.dynamic_variables_ptr, + global_variables_dynamic_size, + MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); + + if (global_lock) + mysql_mutex_lock(&LOCK_global_system_variables); + + mysql_mutex_assert_owner(&LOCK_global_system_variables); + + memcpy(thd->variables.dynamic_variables_ptr + + thd->variables.dynamic_variables_size, + global_system_variables.dynamic_variables_ptr + + thd->variables.dynamic_variables_size, + global_system_variables.dynamic_variables_size - + thd->variables.dynamic_variables_size); + + /* + now we need to iterate through any newly copied 'defaults' + and if it is a string type with MEMALLOC flag, we need to strdup + */ + for (idx= 0; idx < bookmark_hash.records; idx++) + { + sys_var_pluginvar *pi; + sys_var *var; + st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx); + + if (v->version <= thd->variables.dynamic_variables_version) + continue; /* already in thd->variables */ + + if (!(var= intern_find_sys_var(v->key + 1, v->name_len)) || + !(pi= var->cast_pluginvar()) || + v->key[0] != plugin_var_bookmark_key(pi->plugin_var->flags)) + continue; + + /* Here we do anything special that may be required of the data types */ + + if ((pi->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR && + pi->plugin_var->flags & PLUGIN_VAR_MEMALLOC) + { + int offset= ((thdvar_str_t *)(pi->plugin_var))->offset; + char **pp= (char**) (thd->variables.dynamic_variables_ptr + offset); + if (*pp) + *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE)); + } + } + + if (global_lock) + mysql_mutex_unlock(&LOCK_global_system_variables); + + thd->variables.dynamic_variables_version= + global_system_variables.dynamic_variables_version; + thd->variables.dynamic_variables_head= + global_system_variables.dynamic_variables_head; + thd->variables.dynamic_variables_size= + global_system_variables.dynamic_variables_size; +} + + /* Unlocks all system variables which hold a reference */ diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index be1cfcdcc4f..fcc73c83adb 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -174,4 +174,6 @@ typedef my_bool (plugin_foreach_func)(THD *thd, #define plugin_foreach(A,B,C,D) plugin_foreach_with_mask(A,B,C,PLUGIN_IS_READY,D) extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func, int type, uint state_mask, void *arg); + +extern void sync_dynamic_session_variables(THD* thd, bool global_lock); #endif diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 98cade49962..d8ea232caea 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -6937,19 +6937,30 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond) const char *wild= lex->wild ? lex->wild->ptr() : NullS; enum enum_schema_tables schema_table_idx= get_schema_table_idx(tables->schema_table); - enum enum_var_type option_type= OPT_SESSION; + enum enum_var_type scope= OPT_SESSION; bool upper_case_names= (schema_table_idx != SCH_VARIABLES); bool sorted_vars= (schema_table_idx == SCH_VARIABLES); if ((sorted_vars && lex->option_type == OPT_GLOBAL) || schema_table_idx == SCH_GLOBAL_VARIABLES) - option_type= OPT_GLOBAL; + scope= OPT_GLOBAL; COND *partial_cond= make_cond_for_info_schema(cond, tables); mysql_rwlock_rdlock(&LOCK_system_variables_hash); - res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, option_type), - option_type, NULL, "", tables->table, + + /* + Avoid recursive LOCK_system_variables_hash acquisition in + intern_sys_var_ptr() by pre-syncing dynamic session variables. + */ + if (scope == OPT_SESSION && + (!thd->variables.dynamic_variables_ptr || + global_system_variables.dynamic_variables_head > + thd->variables.dynamic_variables_head)) + sync_dynamic_session_variables(thd, true); + + res= show_status_array(thd, wild, enumerate_sys_vars(thd, sorted_vars, scope), + scope, NULL, "", tables->table, upper_case_names, partial_cond); mysql_rwlock_unlock(&LOCK_system_variables_hash); DBUG_RETURN(res); -- cgit v1.2.1 From 19fe10c3e9609d48c1240667e4400395dd8e9a3b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 3 Aug 2016 20:39:47 +0200 Subject: MDEV-6581 Writing to TEMPORARY TABLE not possible in read-only don't mark transactions read-write if no real storage engine is affected (only binlog writes). --- sql/handler.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index d528c0aea7a..5fc75602039 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1238,7 +1238,8 @@ int ha_commit_trans(THD *thd, bool all) uint rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, all); /* rw_trans is TRUE when we in a transaction changing data */ - bool rw_trans= is_real_trans && (rw_ha_count > 0); + bool rw_trans= is_real_trans && + (rw_ha_count > !thd->is_current_stmt_binlog_disabled()); MDL_request mdl_request; if (rw_trans) -- cgit v1.2.1 From 0214115c7f8007a325cf3466a5bc6680e575a119 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 1 Aug 2016 16:53:57 +0200 Subject: trivial cleanup --- sql/sys_vars.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 63d3b388a36..bf7ed231d77 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3025,14 +3025,16 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var) if (!var->save_result.string_value.str) return true; - if (var->save_result.string_value.length > FN_REFLEN) + LEX_STRING *val= &var->save_result.string_value; + + if (val->length > FN_REFLEN) { // path is too long my_error(ER_PATH_LENGTH, MYF(0), self->name.str); return true; } char path[FN_REFLEN]; - size_t path_length= unpack_filename(path, var->save_result.string_value.str); + size_t path_length= unpack_filename(path, val->str); if (!path_length) return true; @@ -3046,9 +3048,9 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var) return false; } - (void) dirname_part(path, var->save_result.string_value.str, &path_length); + (void) dirname_part(path, val->str, &path_length); - if (var->save_result.string_value.length - path_length >= FN_LEN) + if (val->length - path_length >= FN_LEN) { // filename is too long my_error(ER_PATH_LENGTH, MYF(0), self->name.str); return true; -- cgit v1.2.1 From 470f2598cca350b79531bf0b88463a47d94abec3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 3 Aug 2016 20:56:24 +0200 Subject: MDEV-10465 general_log_file can be abused This issue was discovered by Dawid Golunski (http://legalhackers.com) --- sql/sys_vars.cc | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sql') diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index bf7ed231d77..2ed5be3bf3b 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3033,6 +3033,13 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var) return true; } + static const LEX_CSTRING my_cnf= { STRING_WITH_LEN("my.cnf") }; + if (val->length >= my_cnf.length) + { + if (strcasecmp(val->str + val->length - my_cnf.length, my_cnf.str) == 0) + return true; // log file name ends with "my.cnf" + } + char path[FN_REFLEN]; size_t path_length= unpack_filename(path, val->str); -- cgit v1.2.1 From eb32dfd8092a656e2eb77107d8b5d31e143e2cc4 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 3 Aug 2016 11:49:35 +0400 Subject: MDEV-10365 - Race condition in error handling of INSERT DELAYED Shared variables of Delayed_insert may be updated without mutex protection when delayed insert thread gets an error. Re-acquire mutex earlier, so that shared variables are protected. --- sql/sql_insert.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index c60ef6fcc6e..70a12faafb5 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3238,6 +3238,7 @@ bool Delayed_insert::handle_inserts(void) max_rows= 0; // For DBUG output #endif /* Remove all not used rows */ + mysql_mutex_lock(&mutex); while ((row=rows.get())) { if (table->s->blob_fields) @@ -3254,7 +3255,6 @@ bool Delayed_insert::handle_inserts(void) } DBUG_PRINT("error", ("dropped %lu rows after an error", max_rows)); thread_safe_increment(delayed_insert_errors, &LOCK_delayed_status); - mysql_mutex_lock(&mutex); DBUG_RETURN(1); } #endif /* EMBEDDED_LIBRARY */ -- cgit v1.2.1 From 1b3430a5ae6b2f6d5c251f1ff07f5c273b1dc175 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 8 Aug 2016 16:04:40 +0400 Subject: MDEV-10500 CASE/IF Statement returns multiple values and shifts further result values to the next column We assume all around the code that null_value==true is in sync with NULL value returned by val_str()/val_decimal(). Item_sum_sum::val_decimal() erroneously returned a non-NULL value together with null_value set to true. Fixing to return NULL instead. --- sql/item_sum.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_sum.cc b/sql/item_sum.cc index adf48f6feec..445895111ed 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1462,7 +1462,7 @@ my_decimal *Item_sum_sum::val_decimal(my_decimal *val) if (aggr) aggr->endup(); if (hybrid_type == DECIMAL_RESULT) - return (dec_buffs + curr_dec_buff); + return null_value ? NULL : (dec_buffs + curr_dec_buff); return val_decimal_from_real(val); } -- cgit v1.2.1 From 5269d378dfd576ecd03c82b3e763a98c83235636 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 8 Aug 2016 18:37:02 +0400 Subject: MDEV-10468 Assertion `nr >= 0.0' failed in Item_sum_std::val_real() --- sql/item_sum.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 445895111ed..02d2875195d 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1762,6 +1762,8 @@ double Item_sum_std::val_real() { DBUG_ASSERT(fixed == 1); double nr= Item_sum_variance::val_real(); + if (my_isinf(nr)) + return DBL_MAX; DBUG_ASSERT(nr >= 0.0); return sqrt(nr); } -- cgit v1.2.1 From a7c43a684ac390636f2859dfe5cf65fb4be8f75b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 26 Jan 2016 14:49:25 +0200 Subject: MDEV-9304: MariaDB crash with specific query tmp_join may get its tables freed twice during JOIN cleanup. Set them to NULL when the tmp_join is different than the current join. --- sql/sql_union.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sql') diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 87d3e86b2c7..95ce1c9b940 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -887,6 +887,12 @@ bool st_select_lex_unit::cleanup() join->tables_list= 0; join->table_count= 0; join->top_join_tab_count= 0; + if (join->tmp_join && join->tmp_join != join) + { + join->tmp_join->tables_list= 0; + join->tmp_join->table_count= 0; + join->tmp_join->top_join_tab_count= 0; + } } error|= fake_select_lex->cleanup(); /* -- cgit v1.2.1 From 2a54a530a9ba96a9a57607dd156a42192dae0873 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 8 Aug 2016 10:27:22 +0200 Subject: MDEV-10465 general_log_file can be abused followup --- sql/sys_vars.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 2ed5be3bf3b..7d43984c9c0 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3033,19 +3033,19 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var) return true; } - static const LEX_CSTRING my_cnf= { STRING_WITH_LEN("my.cnf") }; - if (val->length >= my_cnf.length) - { - if (strcasecmp(val->str + val->length - my_cnf.length, my_cnf.str) == 0) - return true; // log file name ends with "my.cnf" - } - char path[FN_REFLEN]; size_t path_length= unpack_filename(path, val->str); if (!path_length) return true; + static const LEX_CSTRING my_cnf= { STRING_WITH_LEN("my.cnf") }; + if (path_length >= my_cnf.length) + { + if (strcasecmp(path + path_length - my_cnf.length, my_cnf.str) == 0) + return true; // log file name ends with "my.cnf" + } + MY_STAT f_stat; if (my_stat(path, &f_stat, MYF(0))) -- cgit v1.2.1 From 0098d789c9d8be15d62230289f603ac8f3d5b275 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 9 Aug 2016 13:25:40 +0200 Subject: MDEV-10465 general_log_file can be abused Windows! --- sql/sys_vars.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sql') diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 7d43984c9c0..7b898906184 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3040,10 +3040,14 @@ static bool check_log_path(sys_var *self, THD *thd, set_var *var) return true; static const LEX_CSTRING my_cnf= { STRING_WITH_LEN("my.cnf") }; + static const LEX_CSTRING my_ini= { STRING_WITH_LEN("my.ini") }; if (path_length >= my_cnf.length) { if (strcasecmp(path + path_length - my_cnf.length, my_cnf.str) == 0) return true; // log file name ends with "my.cnf" + DBUG_ASSERT(my_cnf.length == my_ini.length); + if (strcasecmp(path + path_length - my_ini.length, my_ini.str) == 0) + return true; // log file name ends with "my.ini" } MY_STAT f_stat; -- cgit v1.2.1