summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2016-09-09 08:33:08 +0200
committerSergei Golubchik <serg@mariadb.org>2016-09-09 08:33:08 +0200
commit06b7fce9f24116080168b924d17f71b979fc3a14 (patch)
tree5ff9f5684bb118abbee5a9fd3b838d0841661287 /sql
parent1f2ff25eba6c089b2698cd0dab96155ccbf2afd2 (diff)
parent8494039757a2f6353cc161e7824aab4fe2312d2a (diff)
downloadmariadb-git-06b7fce9f24116080168b924d17f71b979fc3a14.tar.gz
Merge branch '10.1' into 10.2
Diffstat (limited to 'sql')
-rw-r--r--sql/contributors.h21
-rw-r--r--sql/handler.cc47
-rw-r--r--sql/handler.h1
-rw-r--r--sql/item.cc31
-rw-r--r--sql/item_func.cc16
-rw-r--r--sql/item_func.h7
-rw-r--r--sql/item_subselect.cc39
-rw-r--r--sql/item_sum.cc14
-rw-r--r--sql/item_timefunc.cc40
-rw-r--r--sql/item_timefunc.h50
-rw-r--r--sql/lock.cc58
-rw-r--r--sql/log.cc57
-rw-r--r--sql/log.h1
-rw-r--r--sql/log_event.cc1
-rw-r--r--sql/mdl.cc67
-rw-r--r--sql/multi_range_read.cc2
-rw-r--r--sql/my_json_writer.cc2
-rw-r--r--sql/mysqld.cc49
-rw-r--r--sql/mysqld.h5
-rw-r--r--sql/net_serv.cc97
-rw-r--r--sql/opt_range.cc69
-rw-r--r--sql/opt_range_mrr.cc6
-rw-r--r--sql/opt_subselect.cc5
-rw-r--r--sql/protocol.cc15
-rw-r--r--sql/rpl_mi.cc7
-rw-r--r--sql/rpl_rli.cc6
-rw-r--r--sql/share/errmsg-utf8.txt4
-rw-r--r--sql/signal_handler.cc23
-rw-r--r--sql/slave.cc5
-rw-r--r--sql/sql_acl.cc10
-rw-r--r--sql/sql_base.cc11
-rw-r--r--sql/sql_class.cc8
-rw-r--r--sql/sql_class.h9
-rw-r--r--sql/sql_delete.cc4
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_parse.cc16
-rw-r--r--sql/sql_plugin.cc127
-rw-r--r--sql/sql_plugin.h4
-rw-r--r--sql/sql_reload.cc6
-rw-r--r--sql/sql_rename.cc33
-rw-r--r--sql/sql_select.cc35
-rw-r--r--sql/sql_select.h5
-rw-r--r--sql/sql_show.cc11
-rw-r--r--sql/sql_table.cc10
-rw-r--r--sql/sql_table.h3
-rw-r--r--sql/sql_update.cc8
-rw-r--r--sql/sys_vars.cc60
-rw-r--r--sql/sys_vars.ic1
-rw-r--r--sql/table.cc8
-rw-r--r--sql/threadpool_common.cc3
-rw-r--r--sql/wsrep_applier.cc10
-rw-r--r--sql/wsrep_binlog.h2
-rw-r--r--sql/wsrep_hton.cc11
-rw-r--r--sql/wsrep_mysqld.cc71
-rw-r--r--sql/wsrep_mysqld.h10
-rw-r--r--sql/wsrep_sst.cc26
-rw-r--r--sql/wsrep_thd.cc14
-rw-r--r--sql/wsrep_var.cc99
-rw-r--r--sql/wsrep_var.h3
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