diff options
author | Sergei Golubchik <serg@mariadb.org> | 2016-09-09 08:33:08 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2016-09-09 08:33:08 +0200 |
commit | 06b7fce9f24116080168b924d17f71b979fc3a14 (patch) | |
tree | 5ff9f5684bb118abbee5a9fd3b838d0841661287 /sql | |
parent | 1f2ff25eba6c089b2698cd0dab96155ccbf2afd2 (diff) | |
parent | 8494039757a2f6353cc161e7824aab4fe2312d2a (diff) | |
download | mariadb-git-06b7fce9f24116080168b924d17f71b979fc3a14.tar.gz |
Merge branch '10.1' into 10.2
Diffstat (limited to 'sql')
59 files changed, 936 insertions, 429 deletions
diff --git a/sql/contributors.h b/sql/contributors.h index 76674d654e5..f52d3243453 100644 --- a/sql/contributors.h +++ b/sql/contributors.h @@ -36,17 +36,16 @@ struct show_table_contributors_st { */ struct show_table_contributors_st show_table_contributors[]= { - /* MariaDB foundation members, in contribution, size , time order */ - {"Booking.com", "http://www.booking.com", "Founding member of the MariaDB Foundation"}, - {"MariaDB Corporation", "https://mariadb.com", "Founding member of the MariaDB Foundation"}, - {"Auttomattic", "http://automattic.com", "Member of the MariaDB Foundation"}, - {"Visma", "http://visma.com", "Member of the MariaDB Foundation"}, - {"Nexedi", "http://www.nexedi.com", "Member of the MariaDB Foundation"}, - {"Acronis", "http://www.acronis.com", "Member of the MariaDB Foundation"}, - - /* Smaller sponsors, newer per year */ - {"Verkkokauppa.com", "Finland", "Sponsor of the MariaDB Foundation"}, - {"Virtuozzo", "https://virtuozzo.com/", "Sponsor of the MariaDB Foundation"}, + /* MariaDB foundation sponsors, in contribution, size , time order */ + {"Booking.com", "http://www.booking.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"}, + {"MariaDB Corporation", "https://mariadb.com", "Founding member, Gold Sponsor of the MariaDB Foundation"}, + {"Visma", "http://visma.com", "Gold Sponsor of the MariaDB Foundation"}, + {"DBS", "http://dbs.com", "Gold Sponsor of the MariaDB Foundation"}, + {"Nexedi", "https://www.nexedi.com", "Silver Sponsor of the MariaDB Foundation"}, + {"Acronis", "http://www.acronis.com", "Silver Sponsor of the MariaDB Foundation"}, + {"Auttomattic", "https://automattic.com", "Bronze Sponsor of the MariaDB Foundation"}, + {"Verkkokauppa.com", "https://virtuozzo.com", "Bronze Sponsor of the MariaDB Foundation"}, + {"Virtuozzo", "https://virtuozzo.com/", "Bronze Sponsor of the MariaDB Foundation"}, /* Sponsors of important features */ {"Google", "USA", "Sponsoring encryption, parallel replication and GTID"}, diff --git a/sql/handler.cc b/sql/handler.cc index 3fbd1b3a71a..589106dfe93 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1357,7 +1357,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; DBUG_PRINT("info", ("is_real_trans: %d rw_trans: %d rw_ha_count: %d", is_real_trans, rw_trans, rw_ha_count)); @@ -2733,6 +2734,15 @@ int handler::ha_index_next_same(uchar *buf, const uchar *key, uint keylen) return result; } + +bool handler::ha_was_semi_consistent_read() +{ + bool result= was_semi_consistent_read(); + if (result) + increment_statistics(&SSV::ha_read_retry_count); + return result; +} + /* Initialize handler for random reading, with error handling */ int handler::ha_rnd_init_with_error(bool scan) @@ -5876,6 +5886,26 @@ int handler::ha_reset() } +static int check_wsrep_max_ws_rows() +{ +#ifdef WITH_WSREP + if (wsrep_max_ws_rows) + { + THD *thd= current_thd; + thd->wsrep_affected_rows++; + if (thd->wsrep_exec_mode != REPL_RECV && + thd->wsrep_affected_rows > wsrep_max_ws_rows) + { + trans_rollback_stmt(thd) || trans_rollback(thd); + my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0)); + return ER_ERROR_DURING_COMMIT; + } + } +#endif /* WITH_WSREP */ + return 0; +} + + int handler::ha_write_row(uchar *buf) { int error; @@ -5899,7 +5929,7 @@ int handler::ha_write_row(uchar *buf) error= binlog_log_row(table, 0, buf, log_func); } DEBUG_SYNC_C("ha_write_row_end"); - DBUG_RETURN(error); + DBUG_RETURN(error ? error : check_wsrep_max_ws_rows()); } @@ -5930,7 +5960,7 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) rows_changed++; error= binlog_log_row(table, old_data, new_data, log_func); } - return error; + return error ? error : check_wsrep_max_ws_rows(); } int handler::ha_delete_row(const uchar *buf) @@ -5957,7 +5987,7 @@ int handler::ha_delete_row(const uchar *buf) rows_changed++; error= binlog_log_row(table, buf, 0, log_func); } - return error; + return error ? error : check_wsrep_max_ws_rows(); } @@ -6088,7 +6118,10 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal) DBUG_RETURN(0); } - THD_TRANS *trans= &victim_thd->transaction.all; + /* Try statement transaction if standard one is not set. */ + THD_TRANS *trans= (victim_thd->transaction.all.ha_list) ? + &victim_thd->transaction.all : &victim_thd->transaction.stmt; + Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; for (; ha_info; ha_info= ha_info_next) @@ -6096,8 +6129,8 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal) handlerton *hton= ha_info->ht(); if (!hton->abort_transaction) { - /* Skip warning for binlog SE */ - if (hton->db_type != DB_TYPE_BINLOG) + /* Skip warning for binlog & wsrep. */ + if (hton->db_type != DB_TYPE_BINLOG && hton != wsrep_hton) { WSREP_WARN("Cannot abort transaction."); } diff --git a/sql/handler.h b/sql/handler.h index cae95ea4ae6..ef0c2f78915 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -3233,6 +3233,7 @@ public: If this method returns nonzero, it will also signal the storage engine that the next read will be a locking re-read of the row. */ + bool ha_was_semi_consistent_read(); virtual bool was_semi_consistent_read() { return 0; } /** Tell the engine whether it should avoid unnecessary lock waits. diff --git a/sql/item.cc b/sql/item.cc index 6a6ace4c844..f79509faed7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -57,6 +57,17 @@ bool cmp_items(Item *a, Item *b) } +/** + Set max_sum_func_level if it is needed +*/ +inline void set_max_sum_func_level(THD *thd, SELECT_LEX *select) +{ + if (thd->lex->in_sum_func && + thd->lex->in_sum_func->nest_level >= select->nest_level) + set_if_bigger(thd->lex->in_sum_func->max_sum_func_level, + select->nest_level - 1); +} + /***************************************************************************** ** Item functions *****************************************************************************/ @@ -5031,6 +5042,11 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) if (rf->fix_fields(thd, reference) || rf->check_cols(1)) return -1; + /* + We can not "move" aggregate function in the place where + its arguments are not defined. + */ + set_max_sum_func_level(thd, select); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, rf, rf); @@ -5039,6 +5055,11 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) } else { + /* + We can not "move" aggregate function in the place where + its arguments are not defined. + */ + set_max_sum_func_level(thd, select); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, this, (Item_ident*)*reference); @@ -5170,6 +5191,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference) return(1); } + /* + We can not "move" aggregate function in the place where + its arguments are not defined. + */ + set_max_sum_func_level(thd, thd->lex->current_select); set_field(new_field); return 0; } @@ -5194,6 +5220,11 @@ bool Item_field::fix_fields(THD *thd, Item **reference) select->parsing_place == IN_GROUP_BY && alias_name_used ? *rf->ref : rf); + /* + We can not "move" aggregate function in the place where + its arguments are not defined. + */ + set_max_sum_func_level(thd, thd->lex->current_select); return FALSE; } } diff --git a/sql/item_func.cc b/sql/item_func.cc index f02c6ca3940..3b98dd0d345 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2273,15 +2273,6 @@ longlong Item_func_bit_neg::val_int() // Conversion functions -void Item_func_integer::fix_length_and_dec() -{ - max_length=args[0]->max_length - args[0]->decimals+1; - uint tmp=float_length(decimals); - set_if_smaller(max_length,tmp); - decimals=0; -} - - void Item_func_int_val::fix_length_and_dec() { DBUG_ENTER("Item_func_int_val::fix_length_and_dec"); @@ -3885,7 +3876,7 @@ longlong Item_master_pos_wait::val_int() longlong timeout = (arg_count>=3) ? args[2]->val_int() : 0 ; String connection_name_buff; LEX_STRING connection_name; - Master_info *mi; + Master_info *mi= NULL; if (arg_count >= 4) { String *con; @@ -3905,8 +3896,9 @@ longlong Item_master_pos_wait::val_int() connection_name= thd->variables.default_master_connection; mysql_mutex_lock(&LOCK_active_mi); - mi= master_info_index->get_master_info(&connection_name, - Sql_condition::WARN_LEVEL_WARN); + if (master_info_index) // master_info_index is set to NULL on shutdown. + mi= master_info_index->get_master_info(&connection_name, + Sql_condition::WARN_LEVEL_WARN); mysql_mutex_unlock(&LOCK_active_mi); if (!mi) goto err; diff --git a/sql/item_func.h b/sql/item_func.h index 44ad4e8a543..ca7c4819012 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1021,13 +1021,6 @@ public: { return get_item_copy<Item_func_cot>(thd, mem_root, this); } }; -class Item_func_integer :public Item_int_func -{ -public: - inline Item_func_integer(THD *thd, Item *a): Item_int_func(thd, a) {} - void fix_length_and_dec(); -}; - class Item_func_int_val :public Item_func_num1 { diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8faf3b43229..21c633333f1 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -564,6 +564,21 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent, bool Item_subselect::is_expensive() { double examined_rows= 0; + bool all_are_simple= true; + + /* check extremely simple select */ + if (!unit->first_select()->next_select()) // no union + { + /* + such single selects works even without optimization because + can not makes loops + */ + SELECT_LEX *sl= unit->first_select(); + JOIN *join = sl->join; + if (join && !join->tables_list && !sl->first_inner_unit()) + return false; + } + for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) { @@ -573,23 +588,27 @@ bool Item_subselect::is_expensive() if (!cur_join) return true; - /* very simple subquery */ - if (!cur_join->tables_list && !sl->first_inner_unit()) - return false; - /* If the subquery is not optimised or in the process of optimization it supposed to be expensive */ - if (!cur_join->optimized) + if (cur_join->optimization_state != JOIN::OPTIMIZATION_DONE) return true; + if (!cur_join->tables_list && !sl->first_inner_unit()) + continue; + /* Subqueries whose result is known after optimization are not expensive. Such subqueries have all tables optimized away, thus have no join plan. */ if ((cur_join->zero_result_cause || !cur_join->tables_list)) - return false; + continue; + + /* + This is not simple SELECT in union so we can not go by simple condition + */ + all_are_simple= false; /* If a subquery is not optimized we cannot estimate its cost. A subquery is @@ -610,7 +629,8 @@ bool Item_subselect::is_expensive() examined_rows+= cur_join->get_examined_rows(); } - return (examined_rows > thd->variables.expensive_subquery_limit); + return !all_are_simple && + (examined_rows > thd->variables.expensive_subquery_limit); } @@ -3680,7 +3700,7 @@ int subselect_single_select_engine::exec() SELECT_LEX *save_select= thd->lex->current_select; thd->lex->current_select= select_lex; - if (!join->optimized) + if (join->optimization_state == JOIN::NOT_OPTIMIZED) { SELECT_LEX_UNIT *unit= select_lex->master_unit(); @@ -5322,7 +5342,8 @@ int subselect_hash_sj_engine::exec() */ thd->lex->current_select= materialize_engine->select_lex; /* The subquery should be optimized, and materialized only once. */ - DBUG_ASSERT(materialize_join->optimized && !is_materialized); + DBUG_ASSERT(materialize_join->optimization_state == JOIN::OPTIMIZATION_DONE && + !is_materialized); materialize_join->exec(); if ((res= MY_TEST(materialize_join->error || thd->is_fatal_error || thd->is_error()))) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index cc7a76213f0..c656d6678fc 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -381,6 +381,16 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref) sl->master_unit()->item->with_sum_func= 1; } thd->lex->current_select->mark_as_dependent(thd, aggr_sel, NULL); + + if ((thd->lex->describe & DESCRIBE_EXTENDED) && aggr_sel) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_WARN_AGGFUNC_DEPENDENCE, + ER_THD(thd, ER_WARN_AGGFUNC_DEPENDENCE), + func_name(), + thd->lex->current_select->select_number, + aggr_sel->select_number); + } return FALSE; } @@ -1422,7 +1432,7 @@ my_decimal *Item_sum_sum::val_decimal(my_decimal *val) if (aggr) aggr->endup(); if (Item_sum_sum::result_type() == DECIMAL_RESULT) - return (dec_buffs + curr_dec_buff); + return null_value ? NULL : (dec_buffs + curr_dec_buff); return val_decimal_from_real(val); } @@ -1756,6 +1766,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); } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index a4a694fe5eb..41dc96717fe 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2201,26 +2201,26 @@ void Item_extract::fix_length_and_dec() { maybe_null=1; // If wrong date switch (int_type) { - case INTERVAL_YEAR: max_length=4; date_value=1; break; - case INTERVAL_YEAR_MONTH: max_length=6; date_value=1; break; - case INTERVAL_QUARTER: max_length=2; date_value=1; break; - case INTERVAL_MONTH: max_length=2; date_value=1; break; - case INTERVAL_WEEK: max_length=2; date_value=1; break; - case INTERVAL_DAY: max_length=2; date_value=1; break; - case INTERVAL_DAY_HOUR: max_length=9; date_value=0; break; - case INTERVAL_DAY_MINUTE: max_length=11; date_value=0; break; - case INTERVAL_DAY_SECOND: max_length=13; date_value=0; break; - case INTERVAL_HOUR: max_length=2; date_value=0; break; - case INTERVAL_HOUR_MINUTE: max_length=4; date_value=0; break; - case INTERVAL_HOUR_SECOND: max_length=6; date_value=0; break; - case INTERVAL_MINUTE: max_length=2; date_value=0; break; - case INTERVAL_MINUTE_SECOND: max_length=4; date_value=0; break; - case INTERVAL_SECOND: max_length=2; date_value=0; break; - case INTERVAL_MICROSECOND: max_length=2; date_value=0; break; - case INTERVAL_DAY_MICROSECOND: max_length=20; date_value=0; break; - case INTERVAL_HOUR_MICROSECOND: max_length=13; date_value=0; break; - case INTERVAL_MINUTE_MICROSECOND: max_length=11; date_value=0; break; - case INTERVAL_SECOND_MICROSECOND: max_length=9; date_value=0; break; + case INTERVAL_YEAR: set_date_length(4); break; // YYYY + case INTERVAL_YEAR_MONTH: set_date_length(6); break; // YYYYMM + case INTERVAL_QUARTER: set_date_length(2); break; // 1..4 + case INTERVAL_MONTH: set_date_length(2); break; // MM + case INTERVAL_WEEK: set_date_length(2); break; // 0..52 + case INTERVAL_DAY: set_date_length(2); break; // DD + case INTERVAL_DAY_HOUR: set_time_length(4); break; // DDhh + case INTERVAL_DAY_MINUTE: set_time_length(6); break; // DDhhmm + case INTERVAL_DAY_SECOND: set_time_length(8); break; // DDhhmmss + case INTERVAL_HOUR: set_time_length(2); break; // hh + case INTERVAL_HOUR_MINUTE: set_time_length(4); break; // hhmm + case INTERVAL_HOUR_SECOND: set_time_length(6); break; // hhmmss + case INTERVAL_MINUTE: set_time_length(2); break; // mm + case INTERVAL_MINUTE_SECOND: set_time_length(4); break; // mmss + case INTERVAL_SECOND: set_time_length(2); break; // ss + case INTERVAL_MICROSECOND: set_time_length(6); break; // ffffff + case INTERVAL_DAY_MICROSECOND: set_time_length(14); break; // DDhhmmssffffff + case INTERVAL_HOUR_MICROSECOND: set_time_length(12); break; // hhmmssffffff + case INTERVAL_MINUTE_MICROSECOND: set_time_length(10); break; // mmssffffff + case INTERVAL_SECOND_MICROSECOND: set_time_length(8); break; // ssffffff case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */ } } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index d9de9b9311a..a853c63128d 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -923,10 +923,57 @@ public: class Item_extract :public Item_int_func { bool date_value; + void set_date_length(uint32 length) + { + /* + Although DATE components (e.g. YEAR, YEAR_MONTH, QUARTER, MONTH, WEEK) + cannot have a sign, we should probably still add +1, + because all around the code we assume that max_length is sign inclusive. + Another options is to set unsigned_flag to "true". + */ + max_length= length; //QQ: see above + date_value= true; + } + void set_time_length(uint32 length) + { + max_length= length + 1/*sign*/; + date_value= false; + } public: const interval_type int_type; // keep it public Item_extract(THD *thd, interval_type type_arg, Item *a): Item_int_func(thd, a), int_type(type_arg) {} + enum_field_types field_type() const + { + switch (int_type) { + case INTERVAL_YEAR: + case INTERVAL_YEAR_MONTH: + case INTERVAL_QUARTER: + case INTERVAL_MONTH: + case INTERVAL_WEEK: + case INTERVAL_DAY: + case INTERVAL_DAY_HOUR: + case INTERVAL_DAY_MINUTE: + case INTERVAL_DAY_SECOND: + case INTERVAL_HOUR: + case INTERVAL_HOUR_MINUTE: + case INTERVAL_HOUR_SECOND: + case INTERVAL_MINUTE: + case INTERVAL_MINUTE_SECOND: + case INTERVAL_SECOND: + case INTERVAL_MICROSECOND: + case INTERVAL_SECOND_MICROSECOND: + return MYSQL_TYPE_LONG; + case INTERVAL_DAY_MICROSECOND: + case INTERVAL_HOUR_MICROSECOND: + case INTERVAL_MINUTE_MICROSECOND: + return MYSQL_TYPE_LONGLONG; + case INTERVAL_LAST: + break; + } + DBUG_ASSERT(0); + return MYSQL_TYPE_LONGLONG; + } longlong val_int(); enum Functype functype() const { return EXTRACT_FUNC; } const char *func_name() const { return "extract"; } @@ -971,6 +1018,9 @@ class Item_extract :public Item_int_func } return true; } + Field *create_field_for_create_select(TABLE *table) + { return tmp_table_field_from_field_type(table, false, false); } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_extract>(thd, mem_root, this); } }; diff --git a/sql/lock.cc b/sql/lock.cc index 07286324fc5..8aebc1f30d9 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -1073,10 +1073,21 @@ void Global_read_lock::unlock_global_read_lock(THD *thd) thd->mdl_context.release_lock(m_mdl_blocks_commits_lock); m_mdl_blocks_commits_lock= NULL; #ifdef WITH_WSREP - if (WSREP_ON) + if (WSREP(thd) || wsrep_node_is_donor()) { wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; wsrep->resume(wsrep); + /* resync here only if we did implicit desync earlier */ + if (!wsrep_desync && wsrep_node_is_synced()) + { + int ret = wsrep->resync(wsrep); + if (ret != WSREP_OK) + { + WSREP_WARN("resync failed %d for FTWRL: db: %s, query: %s", ret, + (thd->db ? thd->db : "(null)"), thd->query()); + DBUG_VOID_RETURN; + } + } } #endif /* WITH_WSREP */ } @@ -1116,14 +1127,11 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd) DBUG_RETURN(0); #ifdef WITH_WSREP - if (WSREP_ON && m_mdl_blocks_commits_lock) + if (WSREP(thd) && m_mdl_blocks_commits_lock) { WSREP_DEBUG("GRL was in block commit mode when entering " "make_global_read_lock_block_commit"); - thd->mdl_context.release_lock(m_mdl_blocks_commits_lock); - m_mdl_blocks_commits_lock= NULL; - wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; - wsrep->resume(wsrep); + DBUG_RETURN(FALSE); } #endif /* WITH_WSREP */ @@ -1137,7 +1145,43 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd) m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT; #ifdef WITH_WSREP - if (WSREP_ON) + /* Native threads should bail out before wsrep oprations to follow. + Donor servicing thread is an exception, it should pause provider but not desync, + as it is already desynced in donor state + */ + if (!WSREP(thd) && !wsrep_node_is_donor()) + { + DBUG_RETURN(FALSE); + } + + /* if already desynced or donor, avoid double desyncing + if not in PC and synced, desyncing is not possible either + */ + if (wsrep_desync || !wsrep_node_is_synced()) + { + WSREP_DEBUG("desync set upfont, skipping implicit desync for FTWRL: %d", + wsrep_desync); + } + else + { + int rcode; + WSREP_DEBUG("running implicit desync for node"); + rcode = wsrep->desync(wsrep); + if (rcode != WSREP_OK) + { + WSREP_WARN("FTWRL desync failed %d for schema: %s, query: %s", + rcode, (thd->db ? thd->db : "(null)"), thd->query()); + my_message(ER_LOCK_DEADLOCK, "wsrep desync failed for FTWRL", MYF(0)); + DBUG_RETURN(TRUE); + } + } + + long long ret = wsrep->pause(wsrep); + if (ret >= 0) + { + wsrep_locked_seqno= ret; + } + else if (ret != -ENOSYS) /* -ENOSYS - no provider */ { long long ret = wsrep->pause(wsrep); if (ret >= 0) diff --git a/sql/log.cc b/sql/log.cc index fa8f10e5464..569942ac485 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3144,6 +3144,22 @@ const char *MYSQL_LOG::generate_name(const char *log_name, } +/* + Print some additional information about addition/removal of + XID list entries. + TODO: Remove once MDEV-9510 is fixed. +*/ +#ifdef WITH_WSREP +#define WSREP_XID_LIST_ENTRY(X, Y) \ + if (wsrep_debug) \ + { \ + char buf[FN_REFLEN]; \ + strmake(buf, Y->binlog_name, Y->binlog_name_len); \ + WSREP_DEBUG(X, buf, Y->binlog_id); \ + } +#else +#define WSREP_XID_LIST_ENTRY(X, Y) do { } while(0) +#endif MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period) :reset_master_pending(0), mark_xid_done_waiting(0), @@ -3212,6 +3228,8 @@ void MYSQL_BIN_LOG::cleanup() */ DBUG_ASSERT(b->xid_count == 0); DBUG_ASSERT(!binlog_xid_count_list.head()); + WSREP_XID_LIST_ENTRY("MYSQL_BIN_LOG::cleanup(): Removing xid_list_entry " + "for %s (%lu)", b); my_free(b); } @@ -3702,7 +3720,14 @@ bool MYSQL_BIN_LOG::open(const char *log_name, new_xid_list_entry->binlog_id= current_binlog_id; /* Remove any initial entries with no pending XIDs. */ while ((b= binlog_xid_count_list.head()) && b->xid_count == 0) + { + WSREP_XID_LIST_ENTRY("MYSQL_BIN_LOG::open(): Removing xid_list_entry for " + "%s (%lu)", b); my_free(binlog_xid_count_list.get()); + } + mysql_cond_broadcast(&COND_xid_list); + WSREP_XID_LIST_ENTRY("MYSQL_BIN_LOG::open(): Adding new xid_list_entry for " + "%s (%lu)", new_xid_list_entry); binlog_xid_count_list.push_back(new_xid_list_entry); mysql_mutex_unlock(&LOCK_xid_list); @@ -4237,8 +4262,11 @@ err: if (b->binlog_id == current_binlog_id) break; DBUG_ASSERT(b->xid_count == 0); + WSREP_XID_LIST_ENTRY("MYSQL_BIN_LOG::reset_logs(): Removing " + "xid_list_entry for %s (%lu)", b); my_free(binlog_xid_count_list.get()); } + mysql_cond_broadcast(&COND_xid_list); reset_master_pending--; mysql_mutex_unlock(&LOCK_xid_list); } @@ -4249,6 +4277,26 @@ err: } +void MYSQL_BIN_LOG::wait_for_last_checkpoint_event() +{ + mysql_mutex_lock(&LOCK_xid_list); + for (;;) + { + if (binlog_xid_count_list.is_last(binlog_xid_count_list.head())) + break; + mysql_cond_wait(&COND_xid_list, &LOCK_xid_list); + } + mysql_mutex_unlock(&LOCK_xid_list); + + /* + LOCK_xid_list and LOCK_log are chained, so the LOCK_log will only be + obtained after mark_xid_done() has written the last checkpoint event. + */ + mysql_mutex_lock(&LOCK_log); + mysql_mutex_unlock(&LOCK_log); +} + + /** Delete relay log files prior to rli->group_relay_log_name (i.e. all logs which are not involved in a non-finished group @@ -7699,7 +7747,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) last= current->next == NULL; if (!current->error && RUN_HOOK(binlog_storage, after_sync, - (current->thd, log_file_name, + (current->thd, current->cache_mngr->last_commit_pos_file, current->cache_mngr->last_commit_pos_offset, first, last))) { @@ -9405,7 +9453,7 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint) */ if (unlikely(reset_master_pending)) { - mysql_cond_signal(&COND_xid_list); + mysql_cond_broadcast(&COND_xid_list); mysql_mutex_unlock(&LOCK_xid_list); DBUG_VOID_RETURN; } @@ -9443,8 +9491,7 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint) mysql_mutex_lock(&LOCK_log); mysql_mutex_lock(&LOCK_xid_list); --mark_xid_done_waiting; - if (unlikely(reset_master_pending)) - mysql_cond_signal(&COND_xid_list); + mysql_cond_broadcast(&COND_xid_list); /* We need to reload current_binlog_id due to release/re-take of lock. */ current= current_binlog_id; @@ -9459,6 +9506,8 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint) DBUG_ASSERT(b); if (b->binlog_id == current || b->xid_count > 0) break; + WSREP_XID_LIST_ENTRY("TC_LOG_BINLOG::mark_xid_done(): Removing " + "xid_list_entry for %s (%lu)", b); my_free(binlog_xid_count_list.get()); } diff --git a/sql/log.h b/sql/log.h index a74a01f9c67..8ddf8641cfa 100644 --- a/sql/log.h +++ b/sql/log.h @@ -791,6 +791,7 @@ public: bool reset_logs(THD* thd, bool create_new_log, rpl_gtid *init_state, uint32 init_state_len, ulong next_log_number); + void wait_for_last_checkpoint_event(); void close(uint exiting); void clear_inuse_flag_when_closing(File file); diff --git a/sql/log_event.cc b/sql/log_event.cc index b1cf6a9024a..9515e5c04a7 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6025,7 +6025,6 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi, new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length); thd->set_db(new_db.str, new_db.length); DBUG_ASSERT(thd->query() == 0); - thd->reset_query_inner(); // Should not be needed thd->is_slave_error= 0; clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); diff --git a/sql/mdl.cc b/sql/mdl.cc index 8fec368e3be..1d6b4f6ffc3 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -17,6 +17,7 @@ #include "sql_class.h" #include "debug_sync.h" #include "sql_array.h" +#include "rpl_rli.h" #include <lf.h> #include <mysqld_error.h> #include <mysql/plugin.h> @@ -506,6 +507,10 @@ public: bitmap_t hog_lock_types_bitmap() const { return m_strategy->hog_lock_types_bitmap(); } +#ifndef DBUG_OFF + bool check_if_conflicting_replication_locks(MDL_context *ctx); +#endif + /** List of granted tickets for this lock. */ Ticket_list m_granted; /** Tickets for contexts waiting to acquire a lock. */ @@ -1977,6 +1982,55 @@ MDL_context::clone_ticket(MDL_request *mdl_request) /** + Check if there is any conflicting lock that could cause this thread + to wait for another thread which is not ready to commit. + This is always an error, as the upper level of parallel replication + should not allow a scheduling of a conflicting DDL until all earlier + transactions has commited. + + This function is only called for a slave using parallel replication + and trying to get an exclusive lock for the table. +*/ + +#ifndef DBUG_OFF +bool MDL_lock::check_if_conflicting_replication_locks(MDL_context *ctx) +{ + Ticket_iterator it(m_granted); + MDL_ticket *conflicting_ticket; + rpl_group_info *rgi_slave= ctx->get_thd()->rgi_slave; + + if (!rgi_slave->gtid_sub_id) + return 0; + + while ((conflicting_ticket= it++)) + { + if (conflicting_ticket->get_ctx() != ctx) + { + MDL_context *conflicting_ctx= conflicting_ticket->get_ctx(); + rpl_group_info *conflicting_rgi_slave; + conflicting_rgi_slave= conflicting_ctx->get_thd()->rgi_slave; + + /* + If the conflicting thread is another parallel replication + thread for the same master and it's not in commit stage, then + the current transaction has started too early and something is + seriously wrong. + */ + if (conflicting_rgi_slave && + conflicting_rgi_slave->gtid_sub_id && + conflicting_rgi_slave->rli == rgi_slave->rli && + conflicting_rgi_slave->current_gtid.domain_id == + rgi_slave->current_gtid.domain_id && + !conflicting_rgi_slave->did_mark_start_commit) + return 1; // Fatal error + } + } + return 0; +} +#endif + + +/** Acquire one lock with waiting for conflicting locks to go away if needed. @param mdl_request [in/out] Lock request object for lock to be acquired @@ -2036,6 +2090,19 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) if (lock->needs_notification(ticket) && lock_wait_timeout) lock->notify_conflicting_locks(this); + /* + Ensure that if we are trying to get an exclusive lock for a slave + running parallel replication, then we are not blocked by another + parallel slave thread that is not committed. This should never happen as + the parallel replication scheduler should never schedule a DDL while + DML's are still running. + */ + DBUG_ASSERT((mdl_request->type != MDL_INTENTION_EXCLUSIVE && + mdl_request->type != MDL_EXCLUSIVE) || + !(get_thd()->rgi_slave && + get_thd()->rgi_slave->is_parallel_exec && + lock->check_if_conflicting_replication_locks(this))); + mysql_prlock_unlock(&lock->m_rwlock); will_wait_for(ticket); diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index 6e8428f1aad..5de9b4a9eec 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -261,7 +261,7 @@ int handler::multi_range_read_next(range_id_t *range_info) } else { - if (was_semi_consistent_read()) + if (ha_was_semi_consistent_read()) { /* The following assignment is redundant, but for extra safety and to diff --git a/sql/my_json_writer.cc b/sql/my_json_writer.cc index e97db210da7..d36fdd1192a 100644 --- a/sql/my_json_writer.cc +++ b/sql/my_json_writer.cc @@ -330,6 +330,8 @@ void Single_line_formatting_helper::flush_on_one_line() ptr++; } owner->output.append(']'); + /* We've printed out the contents of the buffer, mark it as empty */ + buf_ptr= buffer; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ea7bb2b5dcf..ded87d59249 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2761,26 +2761,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 @@ -7771,7 +7762,10 @@ static int show_slaves_running(THD *thd, SHOW_VAR *var, char *buff) var->value= buff; mysql_mutex_lock(&LOCK_active_mi); - *((longlong *)buff)= master_info_index->any_slave_sql_running(); + if (master_info_index) + *((longlong *)buff)= master_info_index->any_slave_sql_running(); + else + *((longlong *)buff)= 0; mysql_mutex_unlock(&LOCK_active_mi); return 0; @@ -8405,6 +8399,7 @@ SHOW_VAR status_vars[]= { {"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG}, {"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_NOFLUSH}, {"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG}, + {"Delete_scan", (char*) offsetof(STATUS_VAR, delete_scan_count), SHOW_LONG_STATUS}, {"Empty_queries", (char*) offsetof(STATUS_VAR, empty_queries), SHOW_LONG_STATUS}, {"Executed_events", (char*) &executed_events, SHOW_LONG_NOFLUSH }, {"Executed_triggers", (char*) offsetof(STATUS_VAR, executed_triggers), SHOW_LONG_STATUS}, @@ -8434,6 +8429,7 @@ SHOW_VAR status_vars[]= { {"Handler_read_last", (char*) offsetof(STATUS_VAR, ha_read_last_count), SHOW_LONG_STATUS}, {"Handler_read_next", (char*) offsetof(STATUS_VAR, ha_read_next_count), SHOW_LONG_STATUS}, {"Handler_read_prev", (char*) offsetof(STATUS_VAR, ha_read_prev_count), SHOW_LONG_STATUS}, + {"Handler_read_retry", (char*) offsetof(STATUS_VAR, ha_read_retry_count), SHOW_LONG_STATUS}, {"Handler_read_rnd", (char*) offsetof(STATUS_VAR, ha_read_rnd_count), SHOW_LONG_STATUS}, {"Handler_read_rnd_deleted", (char*) offsetof(STATUS_VAR, ha_read_rnd_deleted_count), SHOW_LONG_STATUS}, {"Handler_read_rnd_next", (char*) offsetof(STATUS_VAR, ha_read_rnd_next_count), SHOW_LONG_STATUS}, @@ -8555,6 +8551,7 @@ SHOW_VAR status_vars[]= { {"Threads_connected", (char*) &connection_count, SHOW_INT}, {"Threads_created", (char*) &thread_created, SHOW_LONG_NOFLUSH}, {"Threads_running", (char*) &thread_running, SHOW_INT}, + {"Update_scan", (char*) offsetof(STATUS_VAR, update_scan_count), SHOW_LONG_STATUS}, {"Uptime", (char*) &show_starttime, SHOW_SIMPLE_FUNC}, #ifdef ENABLED_PROFILING {"Uptime_since_flush_status",(char*) &show_flushstatustime, SHOW_SIMPLE_FUNC}, @@ -10161,11 +10158,6 @@ PSI_stage_info stage_waiting_for_the_next_event_in_relay_log= { 0, "Waiting for PSI_stage_info stage_waiting_for_the_slave_thread_to_advance_position= { 0, "Waiting for the slave SQL thread to advance position", 0}; PSI_stage_info stage_waiting_to_finalize_termination= { 0, "Waiting to finalize termination", 0}; PSI_stage_info stage_waiting_to_get_readlock= { 0, "Waiting to get readlock", 0}; -PSI_stage_info stage_slave_waiting_workers_to_exit= { 0, "Waiting for workers to exit", 0}; -PSI_stage_info stage_slave_waiting_worker_to_release_partition= { 0, "Waiting for Slave Worker to release partition", 0}; -PSI_stage_info stage_slave_waiting_worker_to_free_events= { 0, "Waiting for Slave Workers to free pending events", 0}; -PSI_stage_info stage_slave_waiting_worker_queue= { 0, "Waiting for Slave Worker queue", 0}; -PSI_stage_info stage_slave_waiting_event_from_coordinator= { 0, "Waiting for an event from Coordinator", 0}; PSI_stage_info stage_binlog_waiting_background_tasks= { 0, "Waiting for background binlog tasks", 0}; PSI_stage_info stage_binlog_processing_checkpoint_notify= { 0, "Processing binlog checkpoint notification", 0}; PSI_stage_info stage_binlog_stopping_background_thread= { 0, "Stopping binlog background thread", 0}; @@ -10261,11 +10253,6 @@ PSI_stage_info *all_server_stages[]= & stage_setup, & stage_show_explain, & stage_slave_has_read_all_relay_log, - & stage_slave_waiting_event_from_coordinator, - & stage_slave_waiting_worker_queue, - & stage_slave_waiting_worker_to_free_events, - & stage_slave_waiting_worker_to_release_partition, - & stage_slave_waiting_workers_to_exit, & stage_sorting, & stage_sorting_for_group, & stage_sorting_for_order, diff --git a/sql/mysqld.h b/sql/mysqld.h index 602cc258943..3356372d3d3 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -475,11 +475,6 @@ extern PSI_stage_info stage_waiting_for_the_next_event_in_relay_log; extern PSI_stage_info stage_waiting_for_the_slave_thread_to_advance_position; extern PSI_stage_info stage_waiting_to_finalize_termination; extern PSI_stage_info stage_waiting_to_get_readlock; -extern PSI_stage_info stage_slave_waiting_worker_to_release_partition; -extern PSI_stage_info stage_slave_waiting_worker_to_free_events; -extern PSI_stage_info stage_slave_waiting_worker_queue; -extern PSI_stage_info stage_slave_waiting_event_from_coordinator; -extern PSI_stage_info stage_slave_waiting_workers_to_exit; extern PSI_stage_info stage_binlog_waiting_background_tasks; extern PSI_stage_info stage_binlog_processing_checkpoint_notify; extern PSI_stage_info stage_binlog_stopping_background_thread; diff --git a/sql/net_serv.cc b/sql/net_serv.cc index dc97d5e8e54..fccc947f3f1 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -552,7 +552,7 @@ net_write_buff(NET *net, const uchar *packet, ulong len) left_length= (ulong) (net->buff_end - net->write_pos); #ifdef DEBUG_DATA_PACKETS - DBUG_DUMP("data", packet, len); + DBUG_DUMP("data_written", packet, len); #endif if (len > left_length) { @@ -641,7 +641,8 @@ net_real_write(NET *net,const uchar *packet, size_t len) } memcpy(b+header_length,packet,len); - if (my_compress(b+header_length, &len, &complen)) + /* Don't compress error packets (compress == 2) */ + if (net->compress == 2 || my_compress(b+header_length, &len, &complen)) complen=0; int3store(&b[NET_HEADER_SIZE],complen); int3store(b,len); @@ -652,7 +653,7 @@ net_real_write(NET *net,const uchar *packet, size_t len) #endif /* HAVE_COMPRESS */ #ifdef DEBUG_DATA_PACKETS - DBUG_DUMP("data", packet, len); + DBUG_DUMP("data_written", packet, len); #endif #ifndef NO_ALARM @@ -842,6 +843,7 @@ my_real_read(NET *net, size_t *complen, size_t length; uint i,retry_count=0; ulong len=packet_error; + my_bool expect_error_packet __attribute__((unused))= 0; thr_alarm_t alarmed; #ifndef NO_ALARM ALARM alarm_buff; @@ -890,6 +892,7 @@ my_real_read(NET *net, size_t *complen, if (i== 0 && thd_net_is_killed()) { + DBUG_PRINT("info", ("thd is killed")); len= packet_error; net->error= 0; net->last_errno= ER_CONNECTION_KILLED; @@ -959,39 +962,34 @@ my_real_read(NET *net, size_t *complen, pos+= length; update_statistics(thd_increment_bytes_received(net->thd, length)); } + +#ifdef DEBUG_DATA_PACKETS + DBUG_DUMP("data_read", net->buff+net->where_b, length); +#endif if (i == 0) { /* First parts is packet length */ ulong helping; +#ifndef DEBUG_DATA_PACKETS DBUG_DUMP("packet_header", net->buff+net->where_b, NET_HEADER_SIZE); +#endif if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr) - { - if (net->buff[net->where_b] != (uchar) 255) - { - DBUG_PRINT("error", - ("Packets out of order (Found: %d, expected %u)", - (int) net->buff[net->where_b + 3], - net->pkt_nr)); - /* - We don't make noise server side, since the client is expected - to break the protocol for e.g. --send LOAD DATA .. LOCAL where - the server expects the client to send a file, but the client - may reply with a new command instead. - */ + { #ifndef MYSQL_SERVER - EXTRA_DEBUG_fflush(stdout); - EXTRA_DEBUG_fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n", - (int) net->buff[net->where_b + 3], - (uint) (uchar) net->pkt_nr); - EXTRA_DEBUG_fflush(stderr); + if (net->buff[net->where_b + 3] == (uchar) (net->pkt_nr -1)) + { + /* + If the server was killed then the server may have missed the + last sent client packet and the packet numbering may be one off. + */ + DBUG_PRINT("warning", ("Found possible out of order packets")); + expect_error_packet= 1; + } + else #endif - } - len= packet_error; - /* Not a NET error on the client. XXX: why? */ - MYSQL_SERVER_my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0)); - goto end; - } - net->compress_pkt_nr= ++net->pkt_nr; + goto packets_out_of_order; + } + net->compress_pkt_nr= ++net->pkt_nr; #ifdef HAVE_COMPRESS if (net->compress) { @@ -1039,6 +1037,21 @@ my_real_read(NET *net, size_t *complen, } #endif } +#ifndef MYSQL_SERVER + else if (expect_error_packet) + { + /* + This check is safe both for compressed and not compressed protocol + as for the compressed protocol errors are not compressed anymore. + */ + if (net->buff[net->where_b] != (uchar) 255) + { + /* Restore pkt_nr to original value */ + net->pkt_nr--; + goto packets_out_of_order; + } + } +#endif } end: @@ -1052,7 +1065,7 @@ end: net->reading_or_writing=0; #ifdef DEBUG_DATA_PACKETS if (len != packet_error) - DBUG_DUMP("data", net->buff+net->where_b, len); + DBUG_DUMP("data_read", net->buff+net->where_b, len); #endif #ifdef MYSQL_SERVER if (server_extension != NULL) @@ -1063,9 +1076,35 @@ end: } #endif return(len); + +packets_out_of_order: + { + DBUG_PRINT("error", + ("Packets out of order (Found: %d, expected %u)", + (int) net->buff[net->where_b + 3], + net->pkt_nr)); + DBUG_ASSERT(0); + /* + We don't make noise server side, since the client is expected + to break the protocol for e.g. --send LOAD DATA .. LOCAL where + the server expects the client to send a file, but the client + may reply with a new command instead. + */ +#ifndef MYSQL_SERVER + EXTRA_DEBUG_fflush(stdout); + EXTRA_DEBUG_fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n", + (int) net->buff[net->where_b + 3], + (uint) (uchar) net->pkt_nr); + EXTRA_DEBUG_fflush(stderr); +#endif + len= packet_error; + MYSQL_SERVER_my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0)); + goto end; + } } + /* Old interface. See my_net_read_packet() for function description */ #undef my_net_read diff --git a/sql/opt_range.cc b/sql/opt_range.cc index bd191f715e0..3ea9f4e5db9 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2428,8 +2428,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, scan_time= read_time= DBL_MAX; if (limit < records) read_time= (double) records + scan_time + 1; // Force to use index - else if (read_time <= 2.0 && !force_quick_range) - DBUG_RETURN(0); /* No need for quick select */ possible_keys.clear_all(); @@ -2699,7 +2697,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, thd->no_errors=0; } - DBUG_EXECUTE("info", print_quick(quick, &needed_reg);); /* @@ -10377,8 +10374,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->user_defined_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, @@ -11904,8 +11903,6 @@ void QUICK_ROR_UNION_SELECT::add_used_key_part_to_set(MY_BITMAP *col_set) *******************************************************************************/ static inline uint get_field_keypart(KEY *index, Field *field); -static inline SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree, - PARAM *param, uint *param_idx); static bool get_sel_arg_for_keypart(Field *field, SEL_ARG *index_range_tree, SEL_ARG **cur_range); static bool get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree, @@ -12179,8 +12176,6 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) (GA1,GA2) are all TRUE. If there is more than one such index, select the first one. Here we set the variables: group_prefix_len and index_info. */ - KEY *cur_index_info= table->key_info; - KEY *cur_index_info_end= cur_index_info + table->s->keys; /* Cost-related variables for the best index so far. */ double best_read_cost= DBL_MAX; ha_rows best_records= 0; @@ -12192,11 +12187,12 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) uint max_key_part; SEL_ARG *cur_index_tree= NULL; ha_rows cur_quick_prefix_records= 0; - uint cur_param_idx=MAX_KEY; - for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ; - cur_index_info++, cur_index++) + // We go through allowed indexes + for (uint cur_param_idx= 0; cur_param_idx < param->keys ; ++cur_param_idx) { + const uint cur_index= param->real_keynr[cur_param_idx]; + KEY *const cur_index_info= &table->key_info[cur_index]; KEY_PART_INFO *cur_part; KEY_PART_INFO *end_part; /* Last part for loops. */ /* Last index part. */ @@ -12219,7 +12215,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) (was also: "Exclude UNIQUE indexes ..." but this was removed because there are cases Loose Scan over a multi-part index is useful). */ - if (!table->covering_keys.is_set(cur_index)) + if (!table->covering_keys.is_set(cur_index) || + !table->keys_in_use_for_group_by.is_set(cur_index)) continue; /* @@ -12398,9 +12395,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) { if (tree) { - uint dummy; - SEL_ARG *index_range_tree= get_index_range_tree(cur_index, tree, param, - &dummy); + SEL_ARG *index_range_tree= tree->keys[cur_param_idx]; if (!get_constant_key_infix(cur_index_info, index_range_tree, first_non_group_part, min_max_arg_part, last_part, thd, cur_key_infix, @@ -12464,9 +12459,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) */ if (tree && min_max_arg_item) { - uint dummy; - SEL_ARG *index_range_tree= get_index_range_tree(cur_index, tree, param, - &dummy); + SEL_ARG *index_range_tree= tree->keys[cur_param_idx]; SEL_ARG *cur_range= NULL; if (get_sel_arg_for_keypart(min_max_arg_part->field, index_range_tree, &cur_range) || @@ -12484,9 +12477,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time) /* Compute the cost of using this index. */ if (tree) { - /* Find the SEL_ARG sub-tree that corresponds to the chosen index. */ - cur_index_tree= get_index_range_tree(cur_index, tree, param, - &cur_param_idx); + cur_index_tree= tree->keys[cur_param_idx]; /* Check if this range tree can be used for prefix retrieval. */ Cost_estimate dummy_cost; uint mrr_flags= HA_MRR_USE_DEFAULT_IMPL; @@ -13020,44 +13011,6 @@ get_field_keypart(KEY *index, Field *field) /* - Find the SEL_ARG sub-tree that corresponds to the chosen index. - - SYNOPSIS - get_index_range_tree() - index [in] The ID of the index being looked for - range_tree[in] Tree of ranges being searched - param [in] PARAM from SQL_SELECT::test_quick_select - param_idx [out] Index in the array PARAM::key that corresponds to 'index' - - DESCRIPTION - - A SEL_TREE contains range trees for all usable indexes. This procedure - finds the SEL_ARG sub-tree for 'index'. The members of a SEL_TREE are - ordered in the same way as the members of PARAM::key, thus we first find - the corresponding index in the array PARAM::key. This index is returned - through the variable param_idx, to be used later as argument of - check_quick_select(). - - RETURN - Pointer to the SEL_ARG subtree that corresponds to index. -*/ - -SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree, PARAM *param, - uint *param_idx) -{ - uint idx= 0; /* Index nr in param->key_parts */ - while (idx < param->keys) - { - if (index == param->real_keynr[idx]) - break; - idx++; - } - *param_idx= idx; - return(range_tree->keys[idx]); -} - - -/* Compute the cost of a quick_group_min_max_select for a particular index. SYNOPSIS diff --git a/sql/opt_range_mrr.cc b/sql/opt_range_mrr.cc index 729c491a6f1..fbccb7c4e1d 100644 --- a/sql/opt_range_mrr.cc +++ b/sql/opt_range_mrr.cc @@ -278,14 +278,14 @@ walk_up_n_right: (1) - range analysis is used for estimating condition selectivity (2) - This is a unique key, and we have conditions for all its user-defined key parts. - (3) - The table uses extended keys, and we have conditions for - all key parts. + (3) - The table uses extended keys, this key covers all components, + and we have conditions for all key parts. */ if (!(cur->min_key_flag & ~NULL_RANGE) && !cur->max_key_flag && (!key_info || // (1) ((uint)key_tree->part+1 == key_info->user_defined_key_parts && // (2) key_info->flags & HA_NOSAME) || // (2) - (seq->param->table->s->use_ext_keys && // (3) + ((key_info->flags & HA_EXT_NOSAME) && // (3) (uint)key_tree->part+1 == key_info->ext_key_parts) // (3) ) && range->start_key.length == range->end_key.length && diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index ef05b768b69..a09826ac2f0 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1560,7 +1560,12 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) { tl->set_tablenr(table_no); if (tl->is_jtbm()) + { tl->jtbm_table_no= table_no; + Item *dummy= tl->jtbm_subselect; + tl->jtbm_subselect->fix_after_pullout(parent_lex, &dummy); + DBUG_ASSERT(dummy == tl->jtbm_subselect); + } SELECT_LEX *old_sl= tl->select_lex; tl->select_lex= parent_join->select_lex; for (TABLE_LIST *emb= tl->embedding; diff --git a/sql/protocol.cc b/sql/protocol.cc index 9ad9269f3b5..be73c94c9b2 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -426,7 +426,8 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err, uint error; char converted_err[MYSQL_ERRMSG_SIZE]; char buff[2+1+SQLSTATE_LENGTH+MYSQL_ERRMSG_SIZE], *pos; - + my_bool ret; + uint8 save_compress; DBUG_ENTER("send_error_packet"); if (net->vio == 0) @@ -454,8 +455,16 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err, /* Converted error message is always null-terminated. */ length= (uint) (strmake(pos, converted_err, MYSQL_ERRMSG_SIZE - 1) - buff); - DBUG_RETURN(net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) buff, - length)); + /* + Ensure that errors are not compressed. This is to ensure we can + detect out of bands error messages in the client + */ + if ((save_compress= net->compress)) + net->compress= 2; + ret= net_write_command(net,(uchar) 255, (uchar*) "", 0, (uchar*) buff, + length); + net->compress= save_compress; + DBUG_RETURN(ret); } #endif /* EMBEDDED_LIBRARY */ diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 02dbac46eb5..6048d26998b 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -1233,8 +1233,6 @@ Master_info_index::get_master_info(const LEX_STRING *connection_name, connection_name->str)); mysql_mutex_assert_owner(&LOCK_active_mi); - if (!this) // master_info_index is set to NULL on server shutdown - DBUG_RETURN(NULL); /* Make name lower case for comparison */ res= strmake(buff, connection_name->str, connection_name->length); @@ -1388,8 +1386,6 @@ bool Master_info_index::give_error_if_slave_running() { DBUG_ENTER("give_error_if_slave_running"); mysql_mutex_assert_owner(&LOCK_active_mi); - if (!this) // master_info_index is set to NULL on server shutdown - DBUG_RETURN(TRUE); for (uint i= 0; i< master_info_hash.records; ++i) { @@ -1420,8 +1416,7 @@ uint Master_info_index::any_slave_sql_running() { uint count= 0; DBUG_ENTER("any_slave_sql_running"); - if (!this) // master_info_index is set to NULL on server shutdown - DBUG_RETURN(count); + mysql_mutex_assert_owner(&LOCK_active_mi); for (uint i= 0; i< master_info_hash.records; ++i) { diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index c1a1c440922..de6e37aecaf 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1939,8 +1939,8 @@ rpl_group_info::mark_start_commit_no_lock() { if (did_mark_start_commit) return; - mark_start_commit_inner(parallel_entry, gco, this); did_mark_start_commit= true; + mark_start_commit_inner(parallel_entry, gco, this); } @@ -1951,12 +1951,12 @@ rpl_group_info::mark_start_commit() if (did_mark_start_commit) return; + did_mark_start_commit= true; e= this->parallel_entry; mysql_mutex_lock(&e->LOCK_parallel_entry); mark_start_commit_inner(e, gco, this); mysql_mutex_unlock(&e->LOCK_parallel_entry); - did_mark_start_commit= true; } @@ -1999,12 +1999,12 @@ rpl_group_info::unmark_start_commit() if (!did_mark_start_commit) return; + did_mark_start_commit= false; e= this->parallel_entry; mysql_mutex_lock(&e->LOCK_parallel_entry); --e->count_committing_event_groups; mysql_mutex_unlock(&e->LOCK_parallel_entry); - did_mark_start_commit= false; } diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 3082508613c..4efc1bdcc43 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7139,6 +7139,10 @@ ER_KILL_QUERY_DENIED_ERROR ER_NO_EIS_FOR_FIELD eng "Engine-independent statistics are not collected for column '%s'" ukr "Незалежна від типу таблиці статистика не збирається для стовбця '%s'" +ER_WARN_AGGFUNC_DEPENDENCE + eng "Aggregate function '%-.192s)' of SELECT #%d belongs to SELECT #%d" + ukr "Агрегатна функція '%-.192s)' з SELECTу #%d належить до SELECTу #%d" + # # Internal errors, not used # diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index ae49e65bb1d..f9478134ab4 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -65,6 +65,12 @@ extern "C" sig_handler handle_fatal_signal(int sig) #ifdef HAVE_STACKTRACE THD *thd; #endif + /* + This flag remembers if the query pointer was found invalid. + We will try and print the query at the end of the signal handler, in case + we're wrong. + */ + bool print_invalid_query_pointer= false; if (segfaulted) { @@ -201,7 +207,12 @@ extern "C" sig_handler handle_fatal_signal(int sig) "Some pointers may be invalid and cause the dump to abort.\n"); my_safe_printf_stderr("Query (%p): ", thd->query()); - my_safe_print_str(thd->query(), MY_MIN(65536U, thd->query_length())); + if (my_safe_print_str(thd->query(), MY_MIN(65536U, thd->query_length()))) + { + // Query was found invalid. We will try to print it at the end. + print_invalid_query_pointer= true; + } + my_safe_printf_stderr("\nConnection ID (thread ID): %lu\n", (ulong) thd->thread_id); my_safe_printf_stderr("Status: %s\n\n", kreason); @@ -265,6 +276,16 @@ extern "C" sig_handler handle_fatal_signal(int sig) "\"mlockall\" bugs.\n"); } + if (print_invalid_query_pointer) + { + my_safe_printf_stderr( + "\nWe think the query pointer is invalid, but we will try " + "to print it anyway. \n" + "Query: "); + my_write_stderr(thd->query(), MY_MIN(65536U, thd->query_length())); + my_safe_printf_stderr("\n\n"); + } + #ifdef HAVE_WRITE_CORE if (test_flags & TEST_CORE_ON_SIGNAL) { diff --git a/sql/slave.cc b/sql/slave.cc index 078307274b0..f0613d048a9 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -647,6 +647,7 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock) mysql_mutex_unlock(log_lock); } if (opt_slave_parallel_threads > 0 && + master_info_index &&// master_info_index is set to NULL on server shutdown !master_info_index->any_slave_sql_running()) rpl_parallel_inactivate_pool(&global_rpl_thread_pool); if (thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL)) @@ -6205,9 +6206,9 @@ static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi, #ifndef DBUG_OFF mi->events_till_disconnect = disconnect_slave_event_count; #endif - ulong client_flag= 0; + ulong client_flag= CLIENT_REMEMBER_OPTIONS; if (opt_slave_compressed_protocol) - client_flag=CLIENT_COMPRESS; /* We will use compression */ + client_flag|= CLIENT_COMPRESS; /* We will use compression */ mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout); mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index fe8e8eea83f..f0f96d340cc 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -31,7 +31,7 @@ #include "sql_base.h" // close_mysql_tables #include "key.h" // key_copy, key_cmp_if_same, key_restore #include "sql_show.h" // append_identifier -#include "sql_table.h" // build_table_filename +#include "sql_table.h" // write_bin_log #include "hash_filo.h" #include "sql_parse.h" // check_access #include "sql_view.h" // VIEW_ANY_ACL @@ -2795,7 +2795,7 @@ bool change_password(THD *thd, LEX_USER *user) if (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0)) { - thd->set_query_inner(buff, query_length, system_charset_info); + thd->set_query(buff, query_length, system_charset_info); WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL); } @@ -2856,7 +2856,7 @@ error: // this label is used in WSREP_TO_ISOLATION_BEGIN { WSREP_TO_ISOLATION_END; - thd->set_query_inner(query_save); + thd->set_query(query_save); thd->wsrep_exec_mode = LOCAL_STATE; } #endif /* WITH_WSREP */ @@ -2920,7 +2920,7 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, if (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0)) { - thd->set_query_inner(buff, query_length, system_charset_info); + thd->set_query(buff, query_length, system_charset_info); WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL); } @@ -3007,7 +3007,7 @@ error: // this label is used in WSREP_TO_ISOLATION_END { WSREP_TO_ISOLATION_END; - thd->set_query_inner(query_save); + thd->set_query(query_save); thd->wsrep_exec_mode = LOCAL_STATE; } #endif /* WITH_WSREP */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7757068b265..9cd8b10331d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. +/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. Copyright (c) 2010, 2016, MariaDB This program is free software; you can redistribute it and/or modify @@ -4211,6 +4211,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; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 54bc4b9959f..c21f8245efc 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1018,6 +1018,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) wsrep_TOI_pre_query_len = 0; wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */ wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED; + wsrep_affected_rows = 0; #endif /* Call to init() below requires fully initialized Open_tables_state. */ reset_open_tables_state(this); @@ -1448,6 +1449,7 @@ void THD::init(void) wsrep_TOI_pre_query = NULL; wsrep_TOI_pre_query_len = 0; wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED; + wsrep_affected_rows = 0; #endif /* WITH_WSREP */ if (variables.sql_log_bin) @@ -2311,6 +2313,8 @@ void THD::cleanup_after_query() #ifdef WITH_WSREP wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED; + if (!in_active_multi_stmt_transaction()) + wsrep_affected_rows= 0; #endif /* WITH_WSREP */ DBUG_VOID_RETURN; @@ -5282,7 +5286,11 @@ void THD::get_definer(LEX_USER *definer, bool role) { binlog_invoker(role); #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) +#ifdef WITH_WSREP + if ((wsrep_applier || slave_thread) && has_invoker()) +#else if (slave_thread && has_invoker()) +#endif { definer->user = invoker_user; definer->host= invoker_host; diff --git a/sql/sql_class.h b/sql/sql_class.h index 02a0523bee2..c316c12549c 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -730,9 +730,11 @@ typedef struct system_status_var ulong ha_read_key_count; ulong ha_read_next_count; ulong ha_read_prev_count; + ulong ha_read_retry_count; ulong ha_read_rnd_count; ulong ha_read_rnd_next_count; ulong ha_read_rnd_deleted_count; + /* This number doesn't include calls to the default implementation and calls made by range access. The intent is to count only calls made by @@ -766,6 +768,8 @@ typedef struct system_status_var ulong select_range_count_; ulong select_range_check_count_; ulong select_scan_count_; + ulong update_scan_count; + ulong delete_scan_count; ulong executed_triggers; ulong long_query_count; ulong filesort_merge_passes_; @@ -3183,12 +3187,12 @@ public: set_start_time(); start_utime= utime_after_lock= microsecond_interval_timer(); } - inline void set_time(my_hrtime_t t) + inline void set_time(my_hrtime_t t) { user_time= t; set_time(); } - inline void set_time(my_time_t t, ulong sec_part) + inline void set_time(my_time_t t, ulong sec_part) { my_hrtime_t hrtime= { hrtime_from_time(t) + sec_part }; set_time(hrtime); @@ -4209,6 +4213,7 @@ public: */ bool wsrep_ignore_table; wsrep_gtid_t wsrep_sync_wait_gtid; + ulong wsrep_affected_rows; #endif /* WITH_WSREP */ /* Handling of timeouts for commands */ diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 95aee805c7f..4f9afca2f6d 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -27,7 +27,6 @@ #include "sql_delete.h" #include "sql_cache.h" // query_cache_* #include "sql_base.h" // open_temprary_table -#include "sql_table.h" // build_table_filename #include "lock.h" // unlock_table_name #include "sql_view.h" // check_key_in_view, mysql_frm_type #include "sql_parse.h" // mysql_init_select @@ -488,6 +487,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DBUG_EXECUTE_IF("show_explain_probe_delete_exec_start", dbug_serve_apcs(thd, 1);); + if (!(select && select->quick)) + status_var_increment(thd->status_var.delete_scan_count); + if (query_plan.using_filesort) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 13943ce8d3c..3025c6e36dc 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3348,6 +3348,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) @@ -3364,7 +3365,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 */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3d123837b99..72630822ad4 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -768,6 +768,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_INSERT_SELECT]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_DELETE]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_DELETE_MULTI]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_RENAME_TABLE]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_REPLACE_SELECT]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES; @@ -7232,6 +7233,7 @@ bool check_stack_overrun(THD *thd, long margin, if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >= (long) (my_thread_stack_size - margin)) { + thd->is_fatal_error= 1; /* Do not use stack for the message buffer to ensure correct behaviour in cases we have close to no stack left. @@ -7320,10 +7322,13 @@ void THD::reset_for_next_command() /* Autoinc variables should be adjusted only for locally executed transactions. Appliers and replayers are either processing ROW - events or get autoinc variable values from Query_log_event. + events or get autoinc variable values from Query_log_event and + mysql slave may be processing STATEMENT format events, but he should + use autoinc values passed in binlog events, not the values forced by + the cluster. */ if (WSREP(thd) && thd->wsrep_exec_mode == LOCAL_STATE && - wsrep_auto_increment_control) + !thd->slave_thread && wsrep_auto_increment_control) { thd->variables.auto_increment_offset= global_system_variables.auto_increment_offset; @@ -7738,10 +7743,9 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, PROCESSLIST. */ if (found_semicolon && (ulong) (found_semicolon - thd->query())) - thd->set_query_inner(thd->query(), - (uint32) (found_semicolon - - thd->query() - 1), - thd->charset()); + thd->set_query(thd->query(), + (uint32) (found_semicolon - thd->query() - 1), + thd->charset()); /* Actually execute the query */ if (found_semicolon) { diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index b715e33ae62..ce46a76d103 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -2977,6 +2977,70 @@ static st_bookmark *register_var(const char *plugin, const char *name, return result; } + +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; +} + + /* returns a pointer to the memory which holds the thd-local variable or a pointer to the global variable if thd==null. @@ -2998,67 +3062,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) - { - 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; - + sync_dynamic_session_variables(thd, global_lock); mysql_rwlock_unlock(&LOCK_system_variables_hash); } DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset); @@ -3592,6 +3597,7 @@ void plugin_opt_set_limits(struct my_option *options, case PLUGIN_VAR_BOOL: options->var_type= GET_BOOL; options->def_value= ((sysvar_bool_t*) opt)->def_val; + options->typelib= &bool_typelib; break; case PLUGIN_VAR_STR: options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ? @@ -3640,6 +3646,7 @@ void plugin_opt_set_limits(struct my_option *options, case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL: options->var_type= GET_BOOL; options->def_value= ((thdvar_bool_t*) opt)->def_val; + options->typelib= &bool_typelib; break; case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL: options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ? diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index 47c3af83bdf..317ccf482b6 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -189,9 +189,13 @@ 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); + extern bool plugin_dl_foreach(THD *thd, const LEX_STRING *dl, plugin_foreach_func *func, void *arg); sys_var *find_sys_var_ex(THD *thd, const char *str, size_t length, bool throw_error, bool locked); + +extern void sync_dynamic_session_variables(THD* thd, bool global_lock); #endif diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index 2fef615831b..2d72d1052d2 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -155,6 +155,12 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, { if (mysql_bin_log.rotate_and_purge(true)) *write_to_binlog= -1; + + if (WSREP_ON) + { + /* Wait for last binlog checkpoint event to be logged. */ + mysql_bin_log.wait_for_last_checkpoint_event(); + } } } if (options & REFRESH_RELAY_LOG) diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index b312077898f..1588644f0e1 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -24,7 +24,7 @@ #include "unireg.h" #include "sql_rename.h" #include "sql_cache.h" // query_cache_* -#include "sql_table.h" // build_table_filename +#include "sql_table.h" // write_bin_log #include "sql_view.h" // mysql_frm_type, mysql_rename_view #include "sql_trigger.h" #include "sql_base.h" // tdc_remove_table, lock_table_names, @@ -211,6 +211,28 @@ static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list) } +static bool +do_rename_temporary(THD *thd, TABLE_LIST *ren_table, TABLE_LIST *new_table, + bool skip_error) +{ + const char *new_alias; + DBUG_ENTER("do_rename_temporary"); + + new_alias= (lower_case_table_names == 2) ? new_table->alias : + new_table->table_name; + + if (is_temporary_table(new_table)) + { + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias); + DBUG_RETURN(1); // This can't be skipped + } + + + DBUG_RETURN(thd->rename_temporary_table(ren_table->table, + new_table->db, new_alias)); +} + + /* Rename a single table or a view @@ -316,6 +338,8 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name, DBUG_RETURN(0); } + + /* Rename all tables in list; Return pointer to wrong entry if something goes wrong. Note that the table_list may be empty! @@ -350,8 +374,11 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) for (ren_table= table_list; ren_table; ren_table= new_table->next_local) { new_table= ren_table->next_local; - if (do_rename(thd, ren_table, new_table->db, new_table->table_name, - new_table->alias, skip_error)) + + if (is_temporary_table(ren_table) ? + do_rename_temporary(thd, ren_table, new_table, skip_error) : + do_rename(thd, ren_table, new_table->db, new_table->table_name, + new_table->alias, skip_error)) DBUG_RETURN(ren_table); } DBUG_RETURN(0); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9bc195074ab..49bc6199d4b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -695,7 +695,7 @@ JOIN::prepare(TABLE_LIST *tables_init, DBUG_ENTER("JOIN::prepare"); // to prevent double initialization on EXPLAIN - if (optimized) + if (optimization_state != JOIN::NOT_OPTIMIZED) DBUG_RETURN(0); conds= conds_init; @@ -1068,24 +1068,13 @@ err: int JOIN::optimize() { - bool was_optimized= optimized; + // to prevent double initialization on EXPLAIN + if (optimization_state != JOIN::NOT_OPTIMIZED) + return FALSE; + optimization_state= JOIN::OPTIMIZATION_IN_PROGRESS; + int res= optimize_inner(); - /* - If we're inside a non-correlated subquery, this function may be - called for the second time after the subquery has been executed - and deleted. The second call will not produce a valid query plan, it will - short-circuit because optimized==TRUE. - - "was_optimized != optimized" is here to handle this case: - - first optimization starts, gets an error (from a const. cheap - subquery), returns 1 - - another JOIN::optimize() call made, and now join->optimize() will - return 0, even though we never had a query plan. - - Can have QEP_NOT_PRESENT_YET for degenerate queries (for example, - SELECT * FROM tbl LIMIT 0) - */ - if (was_optimized != optimized && !res && have_query_plan != QEP_DELETED) + if (!res && have_query_plan != QEP_DELETED) { create_explain_query_if_not_exists(thd->lex, thd->mem_root); have_query_plan= QEP_AVAILABLE; @@ -1112,6 +1101,7 @@ int JOIN::optimize() } } + optimization_state= JOIN::OPTIMIZATION_DONE; return res; } @@ -1139,10 +1129,7 @@ JOIN::optimize_inner() JOIN_TAB *tab; DBUG_ENTER("JOIN::optimize"); do_send_rows = (unit->select_limit_cnt) ? 1 : 0; - // to prevent double initialization on EXPLAIN - if (optimized) - DBUG_RETURN(0); - optimized= 1; + DEBUG_SYNC(thd, "before_join_optimize"); THD_STAGE_INFO(thd, stage_optimizing); @@ -3190,6 +3177,7 @@ void JOIN::exec_inner() { List<Item> *columns_list= &fields_list; DBUG_ENTER("JOIN::exec_inner"); + DBUG_ASSERT(optimization_state == JOIN::OPTIMIZATION_DONE); THD_STAGE_INFO(thd, stage_executing); @@ -15778,7 +15766,7 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) Field_double(max_length, maybe_null, name, decimals, TRUE); break; case INT_RESULT: - /* + /* Select an integer type with the minimal fit precision. convert_int_length is sign inclusive, don't consider the sign. */ @@ -15794,7 +15782,6 @@ Field *Item::create_tmp_field(bool group, TABLE *table, uint convert_int_length) break; case STRING_RESULT: DBUG_ASSERT(collation.collation); - /* GEOMETRY fields have STRING_RESULT result type. To preserve type they needed to be handled separately. diff --git a/sql/sql_select.h b/sql/sql_select.h index cde6209cb7e..fb3f71c0769 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1370,7 +1370,8 @@ public: enum join_optimization_state { NOT_OPTIMIZED=0, OPTIMIZATION_IN_PROGRESS=1, OPTIMIZATION_DONE=2}; - bool optimized; ///< flag to avoid double optimization in EXPLAIN + // state of JOIN optimization + enum join_optimization_state optimization_state; bool initialized; ///< flag to avoid double init_execution calls Explain_select *explain; @@ -1450,7 +1451,7 @@ public: items2.reset(); items3.reset(); zero_result_cause= 0; - optimized= 0; + optimization_state= JOIN::NOT_OPTIMIZED; have_query_plan= QEP_NOT_PRESENT_YET; initialized= 0; cleaned= 0; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 25af6fe07cc..2aa006d5d69 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -7261,6 +7261,17 @@ int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond) COND *partial_cond= make_cond_for_info_schema(thd, cond, tables); mysql_rwlock_rdlock(&LOCK_system_variables_hash); + + /* + 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); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 80fadde714f..0adb21dcb43 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2687,14 +2687,15 @@ bool log_drop_table(THD *thd, const char *db_name, size_t db_name_length, */ bool quick_rm_table(THD *thd, handlerton *base, const char *db, - const char *table_name, uint flags) + const char *table_name, uint flags, const char *table_path) { char path[FN_REFLEN + 1]; bool error= 0; DBUG_ENTER("quick_rm_table"); - uint path_length= build_table_filename(path, sizeof(path) - 1, - db, table_name, reg_ext, flags); + uint path_length= table_path ? + (strxnmov(path, sizeof(path) - 1, table_path, reg_ext, NullS) - path) : + build_table_filename(path, sizeof(path)-1, db, table_name, reg_ext, flags); if (mysql_file_delete(key_file_frm, path, MYF(0))) error= 1; /* purecov: inspected */ path[path_length - reg_ext_length]= '\0'; // Remove reg_ext @@ -9540,7 +9541,8 @@ err_new_table_cleanup: else (void) quick_rm_table(thd, new_db_type, alter_ctx.new_db, alter_ctx.tmp_name, - (FN_IS_TMP | (no_ha_table ? NO_HA_TABLE : 0))); + (FN_IS_TMP | (no_ha_table ? NO_HA_TABLE : 0)), + alter_ctx.get_tmp_path()); /* No default value was provided for a DATE/DATETIME field, the diff --git a/sql/sql_table.h b/sql/sql_table.h index 109da541a28..628c51f678f 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -248,7 +248,8 @@ bool log_drop_table(THD *thd, const char *db_name, size_t db_name_length, const char *table_name, size_t table_name_length, bool temporary_table); bool quick_rm_table(THD *thd, handlerton *base, const char *db, - const char *table_name, uint flags); + const char *table_name, uint flags, + const char *table_path=0); void close_cached_table(THD *thd, TABLE *table); void sp_prepare_create_field(THD *thd, Column_definition *sql_field); int prepare_create_field(Column_definition *sql_field, diff --git a/sql/sql_update.cc b/sql/sql_update.cc index d59b8b7e048..b452e4fe6ae 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -526,6 +526,9 @@ int mysql_update(THD *thd, DBUG_EXECUTE_IF("show_explain_probe_update_exec_start", dbug_serve_apcs(thd, 1);); + if (!(select && select->quick)) + status_var_increment(thd->status_var.update_scan_count); + if (query_plan.using_filesort || query_plan.using_io_buffer) { /* @@ -583,6 +586,7 @@ int mysql_update(THD *thd, close_cached_file(&tempfile); goto err; } + table->file->try_semi_consistent_read(1); /* @@ -621,7 +625,7 @@ int mysql_update(THD *thd, thd->inc_examined_row_count(1); if (!select || (error= select->skip_record(thd)) > 0) { - if (table->file->was_semi_consistent_read()) + if (table->file->ha_was_semi_consistent_read()) continue; /* repeat the read of the same row if it still exists */ explain->buf_tracker.on_record_after_where(); @@ -740,7 +744,7 @@ int mysql_update(THD *thd, thd->inc_examined_row_count(1); if (!select || select->skip_record(thd) > 0) { - if (table->file->was_semi_consistent_read()) + if (table->file->ha_was_semi_consistent_read()) continue; /* repeat the read of the same row if it still exists */ explain->tracker.on_record_after_where(); diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index b0a4b3f99d2..ffc7bb36567 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1594,7 +1594,8 @@ Sys_var_gtid_slave_pos::do_check(THD *thd, set_var *var) } mysql_mutex_lock(&LOCK_active_mi); - running= master_info_index->give_error_if_slave_running(); + running= (!master_info_index || + master_info_index->give_error_if_slave_running()); mysql_mutex_unlock(&LOCK_active_mi); if (running) return true; @@ -1634,7 +1635,7 @@ Sys_var_gtid_slave_pos::global_update(THD *thd, set_var *var) mysql_mutex_unlock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_active_mi); - if (master_info_index->give_error_if_slave_running()) + if (!master_info_index || master_info_index->give_error_if_slave_running()) err= true; else err= rpl_gtid_pos_update(thd, var->save_result.string_value.str, @@ -1823,7 +1824,8 @@ check_slave_parallel_threads(sys_var *self, THD *thd, set_var *var) bool running; mysql_mutex_lock(&LOCK_active_mi); - running= master_info_index->give_error_if_slave_running(); + running= (!master_info_index || + master_info_index->give_error_if_slave_running()); mysql_mutex_unlock(&LOCK_active_mi); if (running) return true; @@ -1838,7 +1840,8 @@ fix_slave_parallel_threads(sys_var *self, THD *thd, enum_var_type type) mysql_mutex_unlock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_active_mi); - err= master_info_index->give_error_if_slave_running(); + err= (!master_info_index || + master_info_index->give_error_if_slave_running()); mysql_mutex_unlock(&LOCK_active_mi); mysql_mutex_lock(&LOCK_global_system_variables); @@ -1874,7 +1877,8 @@ check_slave_domain_parallel_threads(sys_var *self, THD *thd, set_var *var) bool running; mysql_mutex_lock(&LOCK_active_mi); - running= master_info_index->give_error_if_slave_running(); + running= (!master_info_index || + master_info_index->give_error_if_slave_running()); mysql_mutex_unlock(&LOCK_active_mi); if (running) return true; @@ -1889,7 +1893,8 @@ fix_slave_domain_parallel_threads(sys_var *self, THD *thd, enum_var_type type) mysql_mutex_unlock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_active_mi); - running= master_info_index->give_error_if_slave_running(); + running= (!master_info_index || + master_info_index->give_error_if_slave_running()); mysql_mutex_unlock(&LOCK_active_mi); mysql_mutex_lock(&LOCK_global_system_variables); @@ -2039,7 +2044,8 @@ check_gtid_ignore_duplicates(sys_var *self, THD *thd, set_var *var) bool running; mysql_mutex_lock(&LOCK_active_mi); - running= master_info_index->give_error_if_slave_running(); + running= (!master_info_index || + master_info_index->give_error_if_slave_running()); mysql_mutex_unlock(&LOCK_active_mi); if (running) return true; @@ -2054,7 +2060,8 @@ fix_gtid_ignore_duplicates(sys_var *self, THD *thd, enum_var_type type) mysql_mutex_unlock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_active_mi); - running= master_info_index->give_error_if_slave_running(); + running= (!master_info_index || + master_info_index->give_error_if_slave_running()); mysql_mutex_unlock(&LOCK_active_mi); mysql_mutex_lock(&LOCK_global_system_variables); @@ -2960,7 +2967,7 @@ Sys_var_replicate_events_marked_for_skip::global_update(THD *thd, set_var *var) mysql_mutex_unlock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_active_mi); - if (!master_info_index->give_error_if_slave_running()) + if (master_info_index && !master_info_index->give_error_if_slave_running()) result= Sys_var_enum::global_update(thd, var); mysql_mutex_unlock(&LOCK_active_mi); mysql_mutex_lock(&LOCK_global_system_variables); @@ -4011,14 +4018,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; @@ -4031,6 +4040,17 @@ 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; if (my_stat(path, &f_stat, MYF(0))) @@ -4040,9 +4060,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; @@ -4805,9 +4825,10 @@ static Sys_var_mybool Sys_wsrep_auto_increment_control( CMD_LINE(OPT_ARG), DEFAULT(TRUE)); static Sys_var_mybool Sys_wsrep_drupal_282555_workaround( - "wsrep_drupal_282555_workaround", "To use a workaround for" - "bad autoincrement value", - GLOBAL_VAR(wsrep_drupal_282555_workaround), + "wsrep_drupal_282555_workaround", "Enable a workaround to handle the " + "cases where inserting a DEFAULT value into an auto-increment column " + "could fail with duplicate key error", + GLOBAL_VAR(wsrep_drupal_282555_workaround), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); static Sys_var_charptr sys_wsrep_sst_method( @@ -4866,13 +4887,14 @@ static Sys_var_charptr Sys_wsrep_start_position ( static Sys_var_ulong Sys_wsrep_max_ws_size ( "wsrep_max_ws_size", "Max write set size (bytes)", GLOBAL_VAR(wsrep_max_ws_size), CMD_LINE(REQUIRED_ARG), - /* Upper limit is 65K short of 4G to avoid overlows on 32-bit systems */ - VALID_RANGE(1024, WSREP_MAX_WS_SIZE), DEFAULT(1073741824UL), BLOCK_SIZE(1)); + VALID_RANGE(1024, WSREP_MAX_WS_SIZE), DEFAULT(WSREP_MAX_WS_SIZE), + BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(wsrep_max_ws_size_check), ON_UPDATE(wsrep_max_ws_size_update)); static Sys_var_ulong Sys_wsrep_max_ws_rows ( "wsrep_max_ws_rows", "Max number of rows in write set", GLOBAL_VAR(wsrep_max_ws_rows), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(1, 1048576), DEFAULT(131072), BLOCK_SIZE(1)); + VALID_RANGE(0, 1048576), DEFAULT(0), BLOCK_SIZE(1)); static Sys_var_charptr Sys_wsrep_notify_cmd( "wsrep_notify_cmd", "", diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index 6f17e768d95..c7f148afd39 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -96,7 +96,6 @@ enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET}; static const char *bool_values[3]= {"OFF", "ON", 0}; TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 }; -extern const char *encrypt_algorithm_names[]; /** A small wrapper class to pass getopt arguments as a pair diff --git a/sql/table.cc b/sql/table.cc index 42ed08233af..a8a47e7080c 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1948,6 +1948,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, { KEY_PART_INFO *new_key_part= (keyinfo-1)->key_part + (keyinfo-1)->ext_key_parts; + uint add_keyparts_for_this_key= add_first_key_parts; /* Do not extend the key that contains a component @@ -1959,19 +1960,20 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (share->field[fieldnr-1]->key_length() != keyinfo->key_part[i].length) { - add_first_key_parts= 0; + add_keyparts_for_this_key= 0; break; } } - if (add_first_key_parts < keyinfo->ext_key_parts-keyinfo->user_defined_key_parts) + if (add_keyparts_for_this_key < (keyinfo->ext_key_parts - + keyinfo->user_defined_key_parts)) { share->ext_key_parts-= keyinfo->ext_key_parts; key_part_map ext_key_part_map= keyinfo->ext_key_part_map; keyinfo->ext_key_parts= keyinfo->user_defined_key_parts; keyinfo->ext_key_flags= keyinfo->flags; keyinfo->ext_key_part_map= 0; - for (i= 0; i < add_first_key_parts; i++) + for (i= 0; i < add_keyparts_for_this_key; i++) { if (ext_key_part_map & 1<<i) { diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc index a7996efc382..d6c343dc04e 100644 --- a/sql/threadpool_common.cc +++ b/sql/threadpool_common.cc @@ -164,9 +164,8 @@ THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data) if (!setup_connection_thread_globals(thd)) { - if (!login_connection(thd)) + if (!thd_prepare_connection(thd)) { - prepare_new_connection_state(thd); /* Check if THD is ok, as prepare_new_connection_state() diff --git a/sql/wsrep_applier.cc b/sql/wsrep_applier.cc index b4557cfe1b7..059aabe7b46 100644 --- a/sql/wsrep_applier.cc +++ b/sql/wsrep_applier.cc @@ -39,15 +39,9 @@ static Log_event* wsrep_read_log_event( const char *error= 0; Log_event *res= 0; - if (data_len > wsrep_max_ws_size) - { - error = "Event too big"; - goto err; - } - - res= Log_event::read_log_event(buf, data_len, &error, description_event, true); + res= Log_event::read_log_event(buf, data_len, &error, description_event, + true); -err: if (!res) { DBUG_ASSERT(error != 0); diff --git a/sql/wsrep_binlog.h b/sql/wsrep_binlog.h index 1e820529211..864813d5c98 100644 --- a/sql/wsrep_binlog.h +++ b/sql/wsrep_binlog.h @@ -19,7 +19,7 @@ #include "sql_class.h" // THD, IO_CACHE #define HEAP_PAGE_SIZE 65536 /* 64K */ -#define WSREP_MAX_WS_SIZE (0xFFFFFFFFUL - HEAP_PAGE_SIZE) +#define WSREP_MAX_WS_SIZE 2147483647 /* 2GB */ /* Write the contents of a cache to a memory buffer. diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc index fa34a5bbc55..2a93484002e 100644 --- a/sql/wsrep_hton.cc +++ b/sql/wsrep_hton.cc @@ -34,11 +34,14 @@ extern "C" int thd_binlog_format(const MYSQL_THD thd); */ void wsrep_cleanup_transaction(THD *thd) { + if (!WSREP(thd)) return; + if (wsrep_emulate_bin_log) thd_binlog_trx_reset(thd); thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID; thd->wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED; thd->wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED; thd->wsrep_exec_mode= LOCAL_STATE; + thd->wsrep_affected_rows= 0; return; } @@ -109,13 +112,7 @@ void wsrep_register_hton(THD* thd, bool all) */ void wsrep_post_commit(THD* thd, bool all) { - /* - TODO: It can perhaps be fixed in a more elegant fashion by turning off - wsrep_emulate_binlog if wsrep_on=0 on server start. - https://github.com/codership/mysql-wsrep/issues/112 - */ - if (!WSREP_ON) - return; + if (!WSREP(thd)) return; switch (thd->wsrep_exec_mode) { diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 75e15db0b8d..a8253ddf3ad 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -184,7 +184,7 @@ static PSI_file_info wsrep_files[]= my_bool wsrep_inited = 0; // initialized ? -static const wsrep_uuid_t cluster_uuid = WSREP_UUID_UNDEFINED; +static wsrep_uuid_t cluster_uuid = WSREP_UUID_UNDEFINED; static char cluster_uuid_str[40]= { 0, }; static const char* cluster_status_str[WSREP_VIEW_MAX] = { @@ -591,8 +591,7 @@ int wsrep_init() WSREP_ERROR("wsrep_load(%s) failed: %s (%d). Reverting to no provider.", wsrep_provider, strerror(rcode), rcode); strcpy((char*)wsrep_provider, WSREP_NONE); // damn it's a dirty hack - (void) wsrep_init(); - return rcode; + return wsrep_init(); } else /* this is for recursive call above */ { @@ -804,6 +803,9 @@ void wsrep_init_startup (bool first) wsrep_debug, wsrep_convert_LOCK_to_trx, (wsrep_on_fun)wsrep_on); + /* Skip replication start if dummy wsrep provider is loaded */ + if (!strcmp(wsrep_provider, WSREP_NONE)) return; + /* Skip replication start if no cluster address */ if (!wsrep_cluster_address || wsrep_cluster_address[0] == 0) return; @@ -1419,6 +1421,12 @@ static int wsrep_TOI_begin(THD *thd, char *db_, char *table_, case SQLCOM_ALTER_EVENT: buf_err= wsrep_alter_event_query(thd, &buf, &buf_len); break; + case SQLCOM_CREATE_ROLE: + if (sp_process_definer(thd)) + { + WSREP_WARN("Failed to set CREATE ROLE definer for TOI."); + } + /* fallthrough */ default: buf_err= wsrep_to_buf_helper(thd, thd->query(), thd->query_length(), &buf, &buf_len); @@ -1493,19 +1501,15 @@ static int wsrep_RSU_begin(THD *thd, char *db_, char *table_) WSREP_DEBUG("RSU BEGIN: %lld, %d : %s", (long long)wsrep_thd_trx_seqno(thd), thd->wsrep_exec_mode, thd->query() ); - if (!wsrep_desync) + ret = wsrep->desync(wsrep); + if (ret != WSREP_OK) { - ret = wsrep->desync(wsrep); - if (ret != WSREP_OK) - { - WSREP_WARN("RSU desync failed %d for schema: %s, query: %s", - ret, (thd->db ? thd->db : "(null)"), thd->query()); - my_error(ER_LOCK_DEADLOCK, MYF(0)); - return(ret); - } + WSREP_WARN("RSU desync failed %d for schema: %s, query: %s", + ret, (thd->db ? thd->db : "(null)"), thd->query()); + my_error(ER_LOCK_DEADLOCK, MYF(0)); + return(ret); } - else - WSREP_DEBUG("RSU desync skipped: %d", wsrep_desync); + mysql_mutex_lock(&LOCK_wsrep_replaying); wsrep_replaying++; mysql_mutex_unlock(&LOCK_wsrep_replaying); @@ -1520,15 +1524,13 @@ static int wsrep_RSU_begin(THD *thd, char *db_, char *table_) wsrep_replaying--; mysql_mutex_unlock(&LOCK_wsrep_replaying); - if (!wsrep_desync) + ret = wsrep->resync(wsrep); + if (ret != WSREP_OK) { - ret = wsrep->resync(wsrep); - if (ret != WSREP_OK) - { - WSREP_WARN("resync failed %d for schema: %s, query: %s", - ret, (thd->db ? thd->db : "(null)"), thd->query()); - } + WSREP_WARN("resync failed %d for schema: %s, query: %s", + ret, (thd->db ? thd->db : "(null)"), thd->query()); } + my_error(ER_LOCK_DEADLOCK, MYF(0)); return(1); } @@ -1564,18 +1566,15 @@ static void wsrep_RSU_end(THD *thd) (thd->db ? thd->db : "(null)"), thd->query()); } - if (!wsrep_desync) + + ret = wsrep->resync(wsrep); + if (ret != WSREP_OK) { - ret = wsrep->resync(wsrep); - if (ret != WSREP_OK) - { - WSREP_WARN("resync failed %d for schema: %s, query: %s", ret, - (thd->db ? thd->db : "(null)"), thd->query()); - return; - } + WSREP_WARN("resync failed %d for schema: %s, query: %s", ret, + (thd->db ? thd->db : "(null)"), thd->query()); + return; } - else - WSREP_DEBUG("RSU resync skipped: %d", wsrep_desync); + thd->variables.wsrep_on = 1; } @@ -2655,3 +2654,13 @@ void wsrep_aborting_thd_enqueue(THD *thd) aborting->next = wsrep_aborting_thd; wsrep_aborting_thd = aborting; } + +bool wsrep_node_is_donor() +{ + return (WSREP_ON) ? (wsrep_config_state->get_status() == 2) : false; +} + +bool wsrep_node_is_synced() +{ + return (WSREP_ON) ? (wsrep_config_state->get_status() == 4) : false; +} diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index ea81384da75..04ccc1a7e45 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -50,6 +50,7 @@ struct wsrep_thd_shadow { ulong tx_isolation; char *db; size_t db_length; + my_hrtime_t user_time; }; // Global wsrep parameters @@ -168,9 +169,14 @@ extern void wsrep_prepend_PATH (const char* path); /* Other global variables */ extern wsrep_seqno_t wsrep_locked_seqno; -#define WSREP_ON \ +#define WSREP_ON \ (global_system_variables.wsrep_on) +#define WSREP_ON_NEW \ + ((global_system_variables.wsrep_on) && \ + wsrep_provider && \ + strcmp(wsrep_provider, WSREP_NONE)) + #define WSREP(thd) \ (WSREP_ON && wsrep && (thd && thd->variables.wsrep_on)) @@ -307,6 +313,8 @@ void wsrep_replay_transaction(THD *thd); bool wsrep_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, HA_CREATE_INFO *create_info); +bool wsrep_node_is_donor(); +bool wsrep_node_is_synced(); #else /* WITH_WSREP */ diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index ba6bb18bf37..50f54fddc95 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -528,7 +528,7 @@ static void* sst_joiner_thread (void* a) } else { // Scan state ID first followed by wsrep_gtid_domain_id. char uuid[512]; - long int domain_id; + unsigned long int domain_id; size_t len= pos - out + 1; if (len > sizeof(uuid)) goto err; // safety check @@ -542,11 +542,11 @@ static void* sst_joiner_thread (void* a) else if (wsrep_gtid_mode) { errno= 0; /* Reset the errno */ - domain_id= strtol(pos + 1, NULL, 10); + domain_id= strtoul(pos + 1, NULL, 10); err= errno; /* Check if we received a valid gtid_domain_id. */ - if (err == EINVAL || err == ERANGE || domain_id < 0x0 || domain_id > 0xFFFF) + if (err == EINVAL || err == ERANGE) { WSREP_ERROR("Failed to get donor wsrep_gtid_domain_id."); err= EINVAL; @@ -1171,6 +1171,16 @@ wait_signal: if (!err) { sst_disallow_writes (thd.ptr, true); + /* + Lets also keep statements that modify binary logs (like RESET LOGS, + RESET MASTER) from proceeding until the files have been transferred + to the joiner node. + */ + if (mysql_bin_log.is_open()) + { + mysql_mutex_lock(mysql_bin_log.get_log_lock()); + } + locked= true; goto wait_signal; } @@ -1179,6 +1189,11 @@ wait_signal: { if (locked) { + if (mysql_bin_log.is_open()) + { + mysql_mutex_assert_owner(mysql_bin_log.get_log_lock()); + mysql_mutex_unlock(mysql_bin_log.get_log_lock()); + } sst_disallow_writes (thd.ptr, false); thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr); locked= false; @@ -1211,6 +1226,11 @@ wait_signal: if (locked) // don't forget to unlock server before return { + if (mysql_bin_log.is_open()) + { + mysql_mutex_assert_owner(mysql_bin_log.get_log_lock()); + mysql_mutex_unlock(mysql_bin_log.get_log_lock()); + } sst_disallow_writes (thd.ptr, false); thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr); } diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index 36768a37973..a810a5a44ae 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -143,6 +143,9 @@ static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow) shadow->wsrep_exec_mode = thd->wsrep_exec_mode; shadow->vio = thd->net.vio; + // Disable general logging on applier threads + thd->variables.option_bits |= OPTION_LOG_OFF; + // Enable binlogging if opt_log_slave_updates is set if (opt_log_slave_updates) thd->variables.option_bits|= OPTION_BIN_LOG; else @@ -164,6 +167,7 @@ static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow) shadow->db = thd->db; shadow->db_length = thd->db_length; + shadow->user_time = thd->user_time; thd->reset_db(NULL, 0); } @@ -174,6 +178,7 @@ static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow) thd->wsrep_exec_mode = shadow->wsrep_exec_mode; thd->net.vio = shadow->vio; thd->variables.tx_isolation = shadow->tx_isolation; + thd->user_time = shadow->user_time; thd->reset_db(shadow->db, shadow->db_length); delete thd->system_thread_info.rpl_sql_info; @@ -187,6 +192,7 @@ static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow) void wsrep_replay_transaction(THD *thd) { + DBUG_ENTER("wsrep_replay_transaction"); /* checking if BF trx must be replayed */ if (thd->wsrep_conflict_state== MUST_REPLAY) { DBUG_ASSERT(wsrep_thd_trx_seqno(thd)); @@ -195,6 +201,13 @@ void wsrep_replay_transaction(THD *thd) { WSREP_ERROR("replay issue, thd has reported status already"); } + + /* + PS reprepare observer should have been removed already. + open_table() will fail if we have dangling observer here. + */ + DBUG_ASSERT(thd->m_reprepare_observer == NULL); + thd->get_stmt_da()->reset_diagnostics_area(); thd->wsrep_conflict_state= REPLAYING; @@ -301,6 +314,7 @@ void wsrep_replay_transaction(THD *thd) mysql_mutex_unlock(&LOCK_wsrep_replaying); } } + DBUG_VOID_RETURN; } static void wsrep_replication_process(THD *thd) diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index f48f08852dc..bb5ee7baa57 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -193,16 +193,46 @@ bool wsrep_start_position_init (const char* val) return false; } +static int get_provider_option_value(const char* opts, + const char* opt_name, + ulong* opt_value) +{ + int ret= 1; + ulong opt_value_tmp; + char *opt_value_str, *s, *opts_copy= my_strdup(opts, MYF(MY_WME)); + + if ((opt_value_str= strstr(opts_copy, opt_name)) == NULL) + goto end; + opt_value_str= strtok_r(opt_value_str, "=", &s); + if (opt_value_str == NULL) goto end; + opt_value_str= strtok_r(NULL, ";", &s); + if (opt_value_str == NULL) goto end; + + opt_value_tmp= strtoul(opt_value_str, NULL, 10); + if (errno == ERANGE) goto end; + + *opt_value= opt_value_tmp; + ret= 0; + +end: + my_free(opts_copy); + return ret; +} + static bool refresh_provider_options() { + DBUG_ASSERT(wsrep); + WSREP_DEBUG("refresh_provider_options: %s", (wsrep_provider_options) ? wsrep_provider_options : "null"); char* opts= wsrep->options_get(wsrep); if (opts) { - if (wsrep_provider_options) my_free((void *)wsrep_provider_options); - wsrep_provider_options = (char*)my_memdup(opts, strlen(opts) + 1, - MYF(MY_WME)); + wsrep_provider_options_init(opts); + get_provider_option_value(wsrep_provider_options, + (char*)"repl.max_ws_size", + &wsrep_max_ws_size); + free(opts); } else { @@ -317,17 +347,17 @@ void wsrep_provider_init (const char* value) bool wsrep_provider_options_check(sys_var *self, THD* thd, set_var* var) { - return 0; -} - -bool wsrep_provider_options_update(sys_var *self, THD* thd, enum_var_type type) -{ if (wsrep == NULL) { my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) not started", MYF(0)); return true; } + return false; +} +bool wsrep_provider_options_update(sys_var *self, THD* thd, enum_var_type type) +{ + DBUG_ASSERT(wsrep); wsrep_status_t ret= wsrep->options_set(wsrep, wsrep_provider_options); if (ret != WSREP_OK) { @@ -520,6 +550,12 @@ bool wsrep_slave_threads_update (sys_var *self, THD* thd, enum_var_type type) bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var) { + if (wsrep == NULL) + { + my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) not started", MYF(0)); + return true; + } + bool new_wsrep_desync= (bool) var->save_result.ulonglong_value; if (wsrep_desync == new_wsrep_desync) { if (new_wsrep_desync) { @@ -531,20 +567,10 @@ bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var) ER_WRONG_VALUE_FOR_VAR, "'wsrep_desync' is already OFF."); } + return false; } - return 0; -} - -bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type) -{ - if (wsrep == NULL) - { - my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) not started", MYF(0)); - return true; - } - wsrep_status_t ret(WSREP_WARNING); - if (wsrep_desync) { + if (new_wsrep_desync) { ret = wsrep->desync (wsrep); if (ret != WSREP_OK) { WSREP_WARN ("SET desync failed %d for schema: %s, query: %s", ret, @@ -566,6 +592,39 @@ bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type) return false; } +bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type) +{ + DBUG_ASSERT(wsrep); + return false; +} + +bool wsrep_max_ws_size_check(sys_var *self, THD* thd, set_var* var) +{ + if (wsrep == NULL) + { + my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) not started", MYF(0)); + return true; + } + return false; +} + +bool wsrep_max_ws_size_update (sys_var *self, THD *thd, enum_var_type) +{ + DBUG_ASSERT(wsrep); + + char max_ws_size_opt[128]; + my_snprintf(max_ws_size_opt, sizeof(max_ws_size_opt), + "repl.max_ws_size=%d", wsrep_max_ws_size); + wsrep_status_t ret= wsrep->options_set(wsrep, max_ws_size_opt); + if (ret != WSREP_OK) + { + WSREP_ERROR("Set options returned %d", ret); + refresh_provider_options(); + return true; + } + return refresh_provider_options(); +} + static SHOW_VAR wsrep_status_vars[]= { {"connected", (char*) &wsrep_connected, SHOW_BOOL}, diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h index 0eccf64edb8..1509fc7d589 100644 --- a/sql/wsrep_var.h +++ b/sql/wsrep_var.h @@ -91,6 +91,9 @@ extern bool wsrep_slave_threads_update UPDATE_ARGS; extern bool wsrep_desync_check CHECK_ARGS; extern bool wsrep_desync_update UPDATE_ARGS; +extern bool wsrep_max_ws_size_check CHECK_ARGS; +extern bool wsrep_max_ws_size_update UPDATE_ARGS; + #else /* WITH_WSREP */ #define WSREP_NONE |