summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2016-02-06 18:14:54 +0200
committerMonty <monty@mariadb.org>2016-02-06 18:14:54 +0200
commitb2f8d7b41001a5da11b2d99a055a207c3911a213 (patch)
treed108ed6d1f38543305235fec6a63228a5a2f08d5 /sql
parentd4b3a199acb0ddcdedff441ae664b0a2cf2fe8d2 (diff)
parent07b8aefe90ca830d2de068f2966cd2288b158a88 (diff)
downloadmariadb-git-b2f8d7b41001a5da11b2d99a055a207c3911a213.tar.gz
Merge branch '10.1' into 10.2
Conflicts: VERSION cmake/plugin.cmake config.h.cmake configure.cmake plugin/server_audit/server_audit.c sql/sql_yacc.yy
Diffstat (limited to 'sql')
-rw-r--r--sql/item.h45
-rw-r--r--sql/item_cmpfunc.cc192
-rw-r--r--sql/item_cmpfunc.h8
-rw-r--r--sql/item_strfunc.cc6
-rw-r--r--sql/item_strfunc.h10
-rw-r--r--sql/mysqld.cc88
-rw-r--r--sql/net_serv.cc20
-rw-r--r--sql/opt_range.cc16
-rw-r--r--sql/rpl_mi.cc18
-rw-r--r--sql/rpl_mi.h2
-rw-r--r--sql/rpl_rli.cc4
-rw-r--r--sql/share/errmsg-utf8.txt5
-rw-r--r--sql/slave.cc456
-rw-r--r--sql/slave.h12
-rw-r--r--sql/sp_head.cc63
-rw-r--r--sql/sp_head.h3
-rw-r--r--sql/sql_acl.cc173
-rw-r--r--sql/sql_acl.h2
-rw-r--r--sql/sql_admin.cc31
-rw-r--r--sql/sql_base.cc5
-rw-r--r--sql/sql_class.cc13
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_parse.cc7
-rw-r--r--sql/sql_prepare.cc249
-rw-r--r--sql/sql_repl.cc57
-rw-r--r--sql/sql_repl.h1
-rw-r--r--sql/sql_select.cc21
-rw-r--r--sql/sql_show.cc113
-rw-r--r--sql/sql_show.h3
-rw-r--r--sql/sql_string.cc110
-rw-r--r--sql/sql_yacc.yy207
-rw-r--r--sql/structs.h9
-rw-r--r--sql/sys_vars.cc22
-rw-r--r--sql/wsrep_mysqld.cc21
-rw-r--r--sql/wsrep_mysqld.h2
-rw-r--r--sql/wsrep_thd.cc28
36 files changed, 1424 insertions, 599 deletions
diff --git a/sql/item.h b/sql/item.h
index 94107d897d6..d0e4372d53f 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -3683,6 +3683,11 @@ public:
used_tables_cache|= item->used_tables();
const_item_cache&= item->const_item();
}
+ void used_tables_and_const_cache_update_and_join(Item *item)
+ {
+ item->update_used_tables();
+ used_tables_and_const_cache_join(item);
+ }
/*
Call update_used_tables() for all "argc" items in the array "argv"
and join with the current cache.
@@ -3692,10 +3697,7 @@ public:
void used_tables_and_const_cache_update_and_join(uint argc, Item **argv)
{
for (uint i=0 ; i < argc ; i++)
- {
- argv[i]->update_used_tables();
- used_tables_and_const_cache_join(argv[i]);
- }
+ used_tables_and_const_cache_update_and_join(argv[i]);
}
/*
Call update_used_tables() for all items in the list
@@ -3708,10 +3710,7 @@ public:
List_iterator_fast<Item> li(list);
Item *item;
while ((item=li++))
- {
- item->update_used_tables();
- used_tables_and_const_cache_join(item);
- }
+ used_tables_and_const_cache_update_and_join(item);
}
};
@@ -5135,6 +5134,12 @@ public:
return (this->*processor)(arg);
}
virtual Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
+ void split_sum_func2_example(THD *thd, Item **ref_pointer_array,
+ List<Item> &fields, uint flags)
+ {
+ example->split_sum_func2(thd, ref_pointer_array, fields, &example, flags);
+ }
+ Item *get_example() const { return example; }
};
@@ -5239,6 +5244,30 @@ public:
bool cache_value();
};
+
+class Item_cache_str_for_nullif: public Item_cache_str
+{
+public:
+ Item_cache_str_for_nullif(THD *thd, const Item *item)
+ :Item_cache_str(thd, item)
+ { }
+ Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
+ {
+ /**
+ Item_cache_str::safe_charset_converter() returns a new Item_cache
+ with Item_func_conv_charset installed on "example". The original
+ Item_cache is not referenced (neither directly nor recursively)
+ from the result of Item_cache_str::safe_charset_converter().
+
+ For NULLIF() purposes we need a different behavior:
+ we need a new instance of Item_func_conv_charset,
+ with the original Item_cache referenced in args[0]. See MDEV-9181.
+ */
+ return Item::safe_charset_converter(thd, tocs);
+ }
+};
+
+
class Item_cache_row: public Item_cache
{
Item_cache **values;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 0c2d241309d..dc457ed6484 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2526,12 +2526,185 @@ bool Item_func_if::date_op(MYSQL_TIME *ltime, uint fuzzydate)
}
+void Item_func_nullif::split_sum_func(THD *thd, Item **ref_pointer_array,
+ List<Item> &fields, uint flags)
+{
+ if (m_cache)
+ {
+ flags|= SPLIT_SUM_SKIP_REGISTERED; // See Item_func::split_sum_func
+ m_cache->split_sum_func2_example(thd, ref_pointer_array, fields, flags);
+ args[1]->split_sum_func2(thd, ref_pointer_array, fields, &args[1], flags);
+ }
+ else
+ {
+ Item_func::split_sum_func(thd, ref_pointer_array, fields, flags);
+ }
+}
+
+
+void Item_func_nullif::update_used_tables()
+{
+ if (m_cache)
+ {
+ used_tables_and_const_cache_init();
+ used_tables_and_const_cache_update_and_join(m_cache->get_example());
+ used_tables_and_const_cache_update_and_join(arg_count, args);
+ }
+ else
+ {
+ Item_func::update_used_tables();
+ }
+}
+
+
+
void
Item_func_nullif::fix_length_and_dec()
{
if (!args[2]) // Only false if EOM
return;
+ THD *thd= current_thd;
+ /*
+ At prepared statement EXECUTE time, args[0] can already
+ point to a different Item, created during PREPARE time fix_length_and_dec().
+ For example, if character set conversion was needed, arguments can look
+ like this:
+
+ args[0]= > Item_func_conv_charset \
+ l_expr
+ args[2]= >------------------------/
+
+ Otherwise (during PREPARE or convensional execution),
+ args[0] and args[2] should still point to the same original l_expr.
+ */
+ DBUG_ASSERT(args[0] == args[2] || thd->stmt_arena->is_stmt_execute());
+ if (args[0]->type() == SUM_FUNC_ITEM)
+ {
+ /*
+ NULLIF(l_expr, r_expr)
+
+ is calculated in the way to return a result equal to:
+
+ CASE WHEN l_expr = r_expr THEN NULL ELSE r_expr END.
+
+ There's nothing special with r_expr, because it's referenced
+ only by args[1] and nothing else.
+
+ l_expr needs a special treatment, as it's referenced by both
+ args[0] and args[2] initially.
+
+ args[2] is used to return the value. Afrer all transformations
+ (e.g. in fix_length_and_dec(), equal field propagation, etc)
+ args[2] points to a an Item which preserves the exact data type and
+ attributes (e.g. collation) of the original l_expr.
+ It can point:
+ - to the original l_expr
+ - to an Item_cache pointing to l_expr
+ - to a constant of the same data type with l_expr.
+
+ args[0] is used for comparison. It can be replaced:
+
+ - to Item_func_conv_charset by character set aggregation routines
+ - to a constant Item by equal field propagation routines
+ (in case of Item_field)
+
+ The data type and/or the attributes of args[0] can differ from
+ the data type and the attributes of the original l_expr, to make
+ it comparable to args[1] (which points to r_expr or its replacement).
+
+ For aggregate functions we have to wrap the original args[0]/args[2]
+ into Item_cache (see MDEV-9181). In this case the Item_cache
+ instance becomes the subject to character set conversion instead of
+ the original args[0]/args[2], while the original args[0]/args[2] get
+ hidden inside the cache.
+
+ Some examples of what NULLIF can end up with after argument
+ substitution (we don't mention args[1] in some cases for simplicity):
+
+ 1. l_expr is not an aggragate function:
+
+ a. No conversion happened.
+ args[0] and args[2] were not replaced to something else
+ (i.e. neither by character set conversion, nor by propagation):
+
+ args[1] > r_expr
+ args[0] \
+ l_expr
+ args[2] /
+
+ b. Conversion of args[0] happened:
+
+ CREATE OR REPLACE TABLE t1 (
+ a CHAR(10) CHARACTER SET latin1,
+ b CHAR(10) CHARACTER SET utf8);
+ SELECT * FROM t1 WHERE NULLIF(a,b);
+
+ args[1] > r_expr (Item_field for t1.b)
+ args[0] > Item_func_conv_charset\
+ l_expr (Item_field for t1.a)
+ args[2] > ----------------------/
+
+ c. Conversion of args[1] happened:
+
+ CREATE OR REPLACE TABLE t1 (
+ a CHAR(10) CHARACTER SET utf8,
+ b CHAR(10) CHARACTER SET latin1);
+ SELECT * FROM t1 WHERE NULLIF(a,b);
+
+ args[1] > Item_func_conv_charset -> r_expr (Item_field for t1.b)
+ args[0] \
+ l_expr (Item_field for t1.a)
+ args[2] /
+
+ d. Conversion of only args[0] happened (by equal field proparation):
+
+ CREATE OR REPLACE TABLE t1 (
+ a CHAR(10),
+ b CHAR(10));
+ SELECT * FROM t1 WHERE NULLIF(a,b) AND a='a';
+
+ args[1] > r_expr (Item_field for t1.b)
+ args[0] > Item_string('a') (constant replacement for t1.a)
+ args[2] > l_expr (Item_field for t1.a)
+
+ e. Conversion of both args[0] and args[2] happened
+ (by equal field propagation):
+
+ CREATE OR REPLACE TABLE t1 (a INT,b INT);
+ SELECT * FROM t1 WHERE NULLIF(a,b) AND a=5;
+
+ args[1] > r_expr (Item_field for "b")
+ args[0] \
+ Item_int (5) (constant replacement for "a")
+ args[2] /
+
+ 2. In case if l_expr is an aggregate function:
+
+ a. No conversion happened:
+
+ args[0] \
+ Item_cache > l_expr
+ args[2] /
+
+ b. Conversion of args[0] happened:
+
+ args[0] > Item_func_conv_charset \
+ Item_cache > l_expr
+ args[2] >------------------------/
+
+ c. Conversion of both args[0] and args[2] happened.
+ (e.g. by equal expression propagation)
+ TODO: check if it's possible (and add an example query if so).
+ */
+ m_cache= args[0]->cmp_type() == STRING_RESULT ?
+ new (thd->mem_root) Item_cache_str_for_nullif(thd, args[0]) :
+ Item_cache::get_cache(thd, args[0]);
+ m_cache->setup(current_thd, args[0]);
+ m_cache->store(args[0]);
+ m_cache->set_used_tables(args[0]->used_tables());
+ args[0]= args[2]= m_cache;
+ }
set_handler_by_field_type(args[2]->field_type());
collation.set(args[2]->collation);
decimals= args[2]->decimals;
@@ -2606,6 +2779,13 @@ void Item_func_nullif::print(String *str, enum_query_type query_type)
}
+int Item_func_nullif::compare()
+{
+ if (m_cache)
+ m_cache->cache_value();
+ return cmp.compare();
+}
+
/**
@note
Note that we have to evaluate the first argument twice as the compare
@@ -2621,7 +2801,7 @@ Item_func_nullif::real_op()
{
DBUG_ASSERT(fixed == 1);
double value;
- if (!cmp.compare())
+ if (!compare())
{
null_value=1;
return 0.0;
@@ -2636,7 +2816,7 @@ Item_func_nullif::int_op()
{
DBUG_ASSERT(fixed == 1);
longlong value;
- if (!cmp.compare())
+ if (!compare())
{
null_value=1;
return 0;
@@ -2651,7 +2831,7 @@ Item_func_nullif::str_op(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res;
- if (!cmp.compare())
+ if (!compare())
{
null_value=1;
return 0;
@@ -2667,7 +2847,7 @@ Item_func_nullif::decimal_op(my_decimal * decimal_value)
{
DBUG_ASSERT(fixed == 1);
my_decimal *res;
- if (!cmp.compare())
+ if (!compare())
{
null_value=1;
return 0;
@@ -2682,7 +2862,7 @@ bool
Item_func_nullif::date_op(MYSQL_TIME *ltime, uint fuzzydate)
{
DBUG_ASSERT(fixed == 1);
- if (!cmp.compare())
+ if (!compare())
return (null_value= true);
return (null_value= args[2]->get_date(ltime, fuzzydate));
}
@@ -2691,7 +2871,7 @@ Item_func_nullif::date_op(MYSQL_TIME *ltime, uint fuzzydate)
bool
Item_func_nullif::is_null()
{
- return (null_value= (!cmp.compare() ? 1 : args[2]->null_value));
+ return (null_value= (!compare() ? 1 : args[2]->null_value));
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index c14ee42016b..af9e008375a 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -996,10 +996,13 @@ class Item_func_nullif :public Item_func_hybrid_field_type
- Item_field::propagate_equal_fields(ANY_SUBST) for the left "a"
- Item_field::propagate_equal_fields(IDENTITY_SUBST) for the right "a"
*/
+ Item_cache *m_cache;
+ int compare();
public:
// Put "a" to args[0] for comparison and to args[2] for the returned value.
Item_func_nullif(THD *thd, Item *a, Item *b):
- Item_func_hybrid_field_type(thd, a, b, a)
+ Item_func_hybrid_field_type(thd, a, b, a),
+ m_cache(NULL)
{}
bool date_op(MYSQL_TIME *ltime, uint fuzzydate);
double real_op();
@@ -1010,6 +1013,9 @@ public:
uint decimal_precision() const { return args[2]->decimal_precision(); }
const char *func_name() const { return "nullif"; }
void print(String *str, enum_query_type query_type);
+ void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields,
+ uint flags);
+ void update_used_tables();
table_map not_null_tables() const { return 0; }
bool is_null();
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index bc39517a914..e22718029e5 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -3404,7 +3404,7 @@ String *Item_func_conv_charset::val_str(String *str)
String *arg= args[0]->val_str(str);
String_copier_for_item copier(current_thd);
return ((null_value= args[0]->null_value ||
- copier.copy_with_warn(conv_charset, &tmp_value,
+ copier.copy_with_warn(collation.collation, &tmp_value,
arg->charset(), arg->ptr(),
arg->length(), arg->length()))) ?
0 : &tmp_value;
@@ -3412,7 +3412,7 @@ String *Item_func_conv_charset::val_str(String *str)
void Item_func_conv_charset::fix_length_and_dec()
{
- collation.set(conv_charset, DERIVATION_IMPLICIT);
+ DBUG_ASSERT(collation.derivation == DERIVATION_IMPLICIT);
fix_char_length(args[0]->max_char_length());
}
@@ -3421,7 +3421,7 @@ void Item_func_conv_charset::print(String *str, enum_query_type query_type)
str->append(STRING_WITH_LEN("convert("));
args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" using "));
- str->append(conv_charset->csname);
+ str->append(collation.collation->csname);
str->append(')');
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index dfa38d7eed6..0ff38157c25 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -960,20 +960,22 @@ class Item_func_conv_charset :public Item_str_func
String tmp_value;
public:
bool safe;
- CHARSET_INFO *conv_charset; // keep it public
Item_func_conv_charset(THD *thd, Item *a, CHARSET_INFO *cs):
Item_str_func(thd, a)
- { conv_charset= cs; use_cached_value= 0; safe= 0; }
+ {
+ collation.set(cs, DERIVATION_IMPLICIT);
+ use_cached_value= 0; safe= 0;
+ }
Item_func_conv_charset(THD *thd, Item *a, CHARSET_INFO *cs, bool cache_if_const):
Item_str_func(thd, a)
{
- conv_charset= cs;
+ collation.set(cs, DERIVATION_IMPLICIT);
if (cache_if_const && args[0]->const_item() && !args[0]->is_expensive())
{
uint errors= 0;
String tmp, *str= args[0]->val_str(&tmp);
if (!str || str_value.copy(str->ptr(), str->length(),
- str->charset(), conv_charset, &errors))
+ str->charset(), cs, &errors))
null_value= 1;
use_cached_value= 1;
str_value.mark_as_const();
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 0c883de7821..c2da0a6e542 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -5235,49 +5235,6 @@ static int init_server_components()
}
plugins_are_initialized= TRUE; /* Don't separate from init function */
-#ifdef WITH_WSREP
- /* Wait for wsrep threads to get created. */
- if (wsrep_creating_startup_threads == 1) {
- mysql_mutex_lock(&LOCK_thread_count);
- while (wsrep_running_threads < 2)
- {
- mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
- }
-
- /* Now is the time to initialize threads for queries. */
- THD *tmp;
- I_List_iterator<THD> it(threads);
- while ((tmp= it++))
- {
- if (tmp->wsrep_applier == true)
- {
- /*
- Save/restore server_status and variables.option_bits and they get
- altered during init_for_queries().
- */
- unsigned int server_status_saved= tmp->server_status;
- ulonglong option_bits_saved= tmp->variables.option_bits;
-
- /*
- Set THR_THD to temporarily point to this THD to register all the
- variables that allocates memory for this THD.
- */
- THD *current_thd_saved= current_thd;
- set_current_thd(tmp);
-
- tmp->init_for_queries();
-
- /* Restore current_thd. */
- set_current_thd(current_thd_saved);
-
- tmp->server_status= server_status_saved;
- tmp->variables.option_bits= option_bits_saved;
- }
- }
- mysql_mutex_unlock(&LOCK_thread_count);
- }
-#endif
-
/* we do want to exit if there are any other unknown options */
if (remaining_argc > 1)
{
@@ -5925,6 +5882,9 @@ int mysqld_main(int argc, char **argv)
if (Events::init((THD*) 0, opt_noacl || opt_bootstrap))
unireg_abort(1);
+ /* It's now safe to use thread specific memory */
+ mysqld_server_initialized= 1;
+
if (WSREP_ON)
{
if (opt_bootstrap)
@@ -5965,9 +5925,6 @@ int mysqld_main(int argc, char **argv)
}
}
- /* It's now safe to use thread specific memory */
- mysqld_server_initialized= 1;
-
create_shutdown_thread();
start_handle_manager();
@@ -7773,8 +7730,8 @@ static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff,
get_master_info(&thd->variables.default_master_connection,
Sql_condition::WARN_LEVEL_NOTE);
if (mi)
- tmp= (my_bool) (mi->slave_running == MYSQL_SLAVE_RUN_CONNECT &&
- mi->rli.slave_running);
+ tmp= (my_bool) (mi->slave_running == MYSQL_SLAVE_RUN_READING &&
+ mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN);
}
mysql_mutex_unlock(&LOCK_active_mi);
if (mi)
@@ -7785,6 +7742,38 @@ static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff,
}
+/* How many slaves are connected to this master */
+
+static int show_slaves_connected(THD *thd, SHOW_VAR *var, char *buff)
+{
+
+ var->type= SHOW_LONGLONG;
+ var->value= buff;
+ mysql_mutex_lock(&LOCK_slave_list);
+
+ *((longlong *)buff)= slave_list.records;
+
+ mysql_mutex_unlock(&LOCK_slave_list);
+ return 0;
+}
+
+
+/* How many masters this slave is connected to */
+
+
+static int show_slaves_running(THD *thd, SHOW_VAR *var, char *buff)
+{
+ var->type= SHOW_LONGLONG;
+ var->value= buff;
+ mysql_mutex_lock(&LOCK_active_mi);
+
+ *((longlong *)buff)= master_info_index->any_slave_sql_running();
+
+ mysql_mutex_unlock(&LOCK_active_mi);
+ return 0;
+}
+
+
static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff,
enum enum_var_type scope)
{
@@ -8493,6 +8482,9 @@ SHOW_VAR status_vars[]= {
{"Select_scan", (char*) offsetof(STATUS_VAR, select_scan_count_), SHOW_LONG_STATUS},
{"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_INT},
#ifdef HAVE_REPLICATION
+ {"Slaves_connected", (char*) &show_slaves_connected, SHOW_SIMPLE_FUNC },
+ {"Slaves_running", (char*) &show_slaves_running, SHOW_SIMPLE_FUNC },
+ {"Slave_connections", (char*) offsetof(STATUS_VAR, com_register_slave), SHOW_LONG_STATUS},
{"Slave_heartbeat_period", (char*) &show_heartbeat_period, SHOW_SIMPLE_FUNC},
{"Slave_received_heartbeats",(char*) &show_slave_received_heartbeats, SHOW_SIMPLE_FUNC},
{"Slave_retried_transactions",(char*)&slave_retried_transactions, SHOW_LONG},
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index b6da7933bb1..d81c89fe534 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -34,6 +34,7 @@
HFTODO this must be hidden if we don't want client capabilities in
embedded library
*/
+
#include <my_global.h>
#include <mysql.h>
#include <mysql_com.h>
@@ -107,13 +108,12 @@ extern void query_cache_insert(void *thd, const char *packet, ulong length,
unsigned pkt_nr);
#endif // HAVE_QUERY_CACHE
#define update_statistics(A) A
-#else
-#define update_statistics(A)
-#endif
-
-#ifdef MYSQL_SERVER
+extern my_bool thd_net_is_killed();
/* Additional instrumentation hooks for the server */
#include "mysql_com_server.h"
+#else
+#define update_statistics(A)
+#define thd_net_is_killed() 0
#endif
#define TEST_BLOCKING 8
@@ -876,6 +876,16 @@ my_real_read(NET *net, size_t *complen,
DBUG_PRINT("info",("vio_read returned %ld errno: %d",
(long) length, vio_errno(net->vio)));
+
+ if (i== 0 && thd_net_is_killed())
+ {
+ len= packet_error;
+ net->error= 0;
+ net->last_errno= ER_CONNECTION_KILLED;
+ MYSQL_SERVER_my_error(net->last_errno, MYF(0));
+ goto end;
+ }
+
#if !defined(__WIN__) && defined(MYSQL_SERVER)
/*
We got an error that there was no data on the socket. We now set up
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 7e6753e9bf6..ed7e9a56ae5 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -4336,15 +4336,14 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
Field **field= (ppar->part_fields)? part_info->part_field_array :
part_info->subpart_field_array;
bool in_subpart_fields= FALSE;
- uint max_key_len= 0;
- uint cur_key_len= 0;
+ uint total_key_len= 0;
for (uint part= 0; part < total_parts; part++, key_part++)
{
key_part->key= 0;
key_part->part= part;
key_part->length= (uint16)(*field)->key_length();
key_part->store_length= (uint16)get_partition_field_store_length(*field);
- cur_key_len += key_part->store_length;
+ total_key_len += key_part->store_length;
DBUG_PRINT("info", ("part %u length %u store_length %u", part,
key_part->length, key_part->store_length));
@@ -4370,18 +4369,13 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
{
field= part_info->subpart_field_array;
in_subpart_fields= TRUE;
- max_key_len= cur_key_len;
- cur_key_len= 0;
}
}
range_par->key_parts_end= key_part;
- if (cur_key_len > max_key_len)
- max_key_len= cur_key_len;
-
- max_key_len++; /* Take into account the "+1" in QUICK_RANGE::QUICK_RANGE */
- if (!(range_par->min_key= (uchar*)alloc_root(alloc,max_key_len)) ||
- !(range_par->max_key= (uchar*)alloc_root(alloc,max_key_len)))
+ total_key_len++; /* Take into account the "+1" in QUICK_RANGE::QUICK_RANGE */
+ if (!(range_par->min_key= (uchar*)alloc_root(alloc,total_key_len)) ||
+ !(range_par->max_key= (uchar*)alloc_root(alloc,total_key_len)))
{
return true;
}
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index 216fbde0177..df721342d1d 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -35,7 +35,8 @@ Master_info::Master_info(LEX_STRING *connection_name_arg,
rli(is_slave_recovery), port(MYSQL_PORT),
checksum_alg_before_fd(BINLOG_CHECKSUM_ALG_UNDEF),
connect_retry(DEFAULT_CONNECT_RETRY), inited(0), abort_slave(0),
- slave_running(0), slave_run_id(0), clock_diff_with_master(0),
+ slave_running(MYSQL_SLAVE_NOT_RUN), slave_run_id(0),
+ clock_diff_with_master(0),
sync_counter(0), heartbeat_period(0), received_heartbeats(0),
master_id(0), prev_master_id(0),
using_gtid(USE_GTID_NO), events_queued_since_last_gtid(0),
@@ -1396,23 +1397,24 @@ bool Master_info_index::give_error_if_slave_running()
The LOCK_active_mi must be held while calling this function.
@return
- TRUE If some slave SQL thread is running.
- FALSE No slave SQL thread is running
+ 0 No Slave SQL thread is running
+ # Number of slave SQL thread running
*/
-bool Master_info_index::any_slave_sql_running()
+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(TRUE);
+ DBUG_RETURN(count);
for (uint i= 0; i< master_info_hash.records; ++i)
{
Master_info *mi= (Master_info *)my_hash_element(&master_info_hash, i);
if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN)
- DBUG_RETURN(TRUE);
+ count++;
}
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(count);
}
@@ -1442,7 +1444,7 @@ bool Master_info_index::start_all_slaves(THD *thd)
Try to start all slaves that are configured (host is defined)
and are not already running
*/
- if ((mi->slave_running != MYSQL_SLAVE_RUN_CONNECT ||
+ if ((mi->slave_running == MYSQL_SLAVE_NOT_RUN ||
!mi->rli.slave_running) && *mi->host)
{
if ((error= start_slave(thd, mi, 1)))
diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h
index 69d602c1dcb..9365c065ea9 100644
--- a/sql/rpl_mi.h
+++ b/sql/rpl_mi.h
@@ -345,7 +345,7 @@ public:
Master_info *get_master_info(const LEX_STRING *connection_name,
Sql_condition::enum_warning_level warning);
bool give_error_if_slave_running();
- bool any_slave_sql_running();
+ uint any_slave_sql_running();
bool start_all_slaves(THD *thd);
bool stop_all_slaves(THD *thd);
};
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 987e011d5eb..2dd6f7d7afc 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -63,7 +63,7 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery)
last_master_timestamp(0), sql_thread_caught_up(true), slave_skip_counter(0),
abort_pos_wait(0), slave_run_id(0), sql_driver_thd(),
gtid_skip_flag(GTID_SKIP_NOT), inited(0), abort_slave(0), stop_for_until(0),
- slave_running(0), until_condition(UNTIL_NONE),
+ slave_running(MYSQL_SLAVE_NOT_RUN), until_condition(UNTIL_NONE),
until_log_pos(0), retried_trans(0), executed_entries(0),
m_flags(0)
{
@@ -389,6 +389,7 @@ Failed to open the existing relay log info file '%s' (errno %d)",
if (rli->is_relay_log_recovery && init_recovery(rli->mi, &msg))
goto err;
+ rli->relay_log_state.load(rpl_global_gtid_slave_state);
if (init_relay_log_pos(rli,
rli->group_relay_log_name,
rli->group_relay_log_pos,
@@ -1148,6 +1149,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
error=1;
goto err;
}
+ rli->relay_log_state.load(rpl_global_gtid_slave_state);
if (!just_reset)
{
/* Save name of used relay log file */
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 0afd13eb19b..376cd7a82ef 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7106,7 +7106,7 @@ ER_PRIOR_COMMIT_FAILED
ER_IT_IS_A_VIEW 42S02
eng "'%-.192s' is a view"
ER_SLAVE_SKIP_NOT_IN_GTID
- eng "When using GTID, @@sql_slave_skip_counter can not be used. Instead, setting @@gtid_slave_pos explicitly can be used to skip to after a given GTID position."
+ eng "When using parallel replication and GTID with multiple replication domains, @@sql_slave_skip_counter can not be used. Instead, setting @@gtid_slave_pos explicitly can be used to skip to after a given GTID position."
ER_TABLE_DEFINITION_TOO_BIG
eng "The definition for table %`s is too big"
ER_PLUGIN_INSTALLED
@@ -7136,3 +7136,6 @@ ER_KILL_QUERY_DENIED_ERROR
eng "You are not owner of query %lu"
ger "Sie sind nicht Eigentümer von Abfrage %lu"
rus "Вы не являетесь владельцем запроса %lu"
+ER_NO_EIS_FOR_FIELD
+ eng "Engine-independent statistics are not collected for column '%s'"
+ ukr "Незалежна від типу таблиці статистика не збирається для стовбця '%s'"
diff --git a/sql/slave.cc b/sql/slave.cc
index 8512fc229c1..72bed45d245 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -117,7 +117,7 @@ static const char *reconnect_messages[SLAVE_RECON_ACT_MAX][SLAVE_RECON_MSG_MAX]=
{
{
"Waiting to reconnect after a failed registration on master",
- "Slave I/O thread killed while waitnig to reconnect after a failed \
+ "Slave I/O thread killed while waiting to reconnect after a failed \
registration on master",
"Reconnecting after a failed registration on master",
"failed registering on master, reconnecting to try again, \
@@ -163,7 +163,6 @@ static int queue_event(Master_info* mi,const char* buf,ulong event_len);
static int terminate_slave_thread(THD *, mysql_mutex_t *, mysql_cond_t *,
volatile uint *, bool);
static bool check_io_slave_killed(Master_info *mi, const char *info);
-static bool send_show_master_info_header(THD *, bool, size_t);
static bool send_show_master_info_data(THD *, Master_info *, bool, String *);
/*
Function to set the slave's max_allowed_packet based on the value
@@ -2497,10 +2496,13 @@ bool show_master_info(THD *thd, Master_info *mi, bool full)
{
DBUG_ENTER("show_master_info");
String gtid_pos;
+ List<Item> field_list;
if (full && rpl_global_gtid_slave_state->tostring(&gtid_pos, NULL, 0))
DBUG_RETURN(TRUE);
- if (send_show_master_info_header(thd, full, gtid_pos.length()))
+ show_master_info_get_fields(thd, &field_list, full, gtid_pos.length());
+ if (thd->protocol->send_result_set_metadata(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
if (send_show_master_info_data(thd, mi, full, &gtid_pos))
DBUG_RETURN(TRUE);
@@ -2508,226 +2510,222 @@ bool show_master_info(THD *thd, Master_info *mi, bool full)
DBUG_RETURN(FALSE);
}
-static bool send_show_master_info_header(THD *thd, bool full,
- size_t gtid_pos_length)
+void show_master_info_get_fields(THD *thd, List<Item> *field_list,
+ bool full, size_t gtid_pos_length)
{
- List<Item> field_list;
- Protocol *protocol= thd->protocol;
Master_info *mi;
MEM_ROOT *mem_root= thd->mem_root;
- DBUG_ENTER("show_master_info_header");
+ DBUG_ENTER("show_master_info_get_fields");
if (full)
{
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Connection_name",
- MAX_CONNECTION_NAME),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Slave_SQL_State", 30),
- thd->mem_root);
- }
-
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Slave_IO_State", 30),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_Host", sizeof(mi->host)),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_User", sizeof(mi->user)),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Master_Port", 7, MYSQL_TYPE_LONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Connect_Retry", 10,
- MYSQL_TYPE_LONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_Log_File", FN_REFLEN),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Read_Master_Log_Pos", 10,
- MYSQL_TYPE_LONGLONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Relay_Log_File", FN_REFLEN),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Relay_Log_Pos", 10,
- MYSQL_TYPE_LONGLONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Relay_Master_Log_File",
- FN_REFLEN),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Slave_IO_Running", 3),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Slave_SQL_Running", 3),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Replicate_Do_DB", 20),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Replicate_Ignore_DB", 20),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Replicate_Do_Table", 20),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Replicate_Ignore_Table", 23),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Replicate_Wild_Do_Table", 24),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Replicate_Wild_Ignore_Table",
- 28),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Last_Errno", 4, MYSQL_TYPE_LONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Last_Error", 20),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Skip_Counter", 10,
- MYSQL_TYPE_LONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Exec_Master_Log_Pos", 10,
- MYSQL_TYPE_LONGLONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Relay_Log_Space", 10,
- MYSQL_TYPE_LONGLONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Until_Condition", 6),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Until_Log_File", FN_REFLEN),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Until_Log_Pos", 10,
- MYSQL_TYPE_LONGLONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_SSL_Allowed", 7),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_SSL_CA_File",
- sizeof(mi->ssl_ca)),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_SSL_CA_Path",
- sizeof(mi->ssl_capath)),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_SSL_Cert",
- sizeof(mi->ssl_cert)),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_SSL_Cipher",
- sizeof(mi->ssl_cipher)),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_SSL_Key",
- sizeof(mi->ssl_key)),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Seconds_Behind_Master", 10,
- MYSQL_TYPE_LONGLONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_SSL_Verify_Server_Cert",
- 3),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Last_IO_Errno", 4,
- MYSQL_TYPE_LONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Last_IO_Error", 20),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Last_SQL_Errno", 4,
- MYSQL_TYPE_LONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Last_SQL_Error", 20),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Replicate_Ignore_Server_Ids",
- FN_REFLEN),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Master_Server_Id", sizeof(ulong),
- MYSQL_TYPE_LONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_SSL_Crl",
- sizeof(mi->ssl_crl)),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Master_SSL_Crlpath",
- sizeof(mi->ssl_crlpath)),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Using_Gtid",
- sizeof("Current_Pos")-1),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Gtid_IO_Pos", 30),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Replicate_Do_Domain_Ids",
- FN_REFLEN),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Replicate_Ignore_Domain_Ids",
- FN_REFLEN),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Parallel_Mode",
- sizeof("conservative")-1),
- thd->mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Connection_name",
+ MAX_CONNECTION_NAME),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Slave_SQL_State", 30),
+ mem_root);
+ }
+
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Slave_IO_State", 30),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_Host", sizeof(mi->host)),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_User", sizeof(mi->user)),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Master_Port", 7, MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Connect_Retry", 10,
+ MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_Log_File", FN_REFLEN),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Read_Master_Log_Pos", 10,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Relay_Log_File", FN_REFLEN),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Relay_Log_Pos", 10,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Relay_Master_Log_File",
+ FN_REFLEN),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Slave_IO_Running", 3),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Slave_SQL_Running", 3),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Replicate_Do_DB", 20),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Replicate_Ignore_DB", 20),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Replicate_Do_Table", 20),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Replicate_Ignore_Table", 23),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Replicate_Wild_Do_Table", 24),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Replicate_Wild_Ignore_Table",
+ 28),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Last_Errno", 4, MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Last_Error", 20),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Skip_Counter", 10,
+ MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Exec_Master_Log_Pos", 10,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Relay_Log_Space", 10,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Until_Condition", 6),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Until_Log_File", FN_REFLEN),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Until_Log_Pos", 10,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_SSL_Allowed", 7),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_SSL_CA_File",
+ sizeof(mi->ssl_ca)),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_SSL_CA_Path",
+ sizeof(mi->ssl_capath)),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_SSL_Cert",
+ sizeof(mi->ssl_cert)),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_SSL_Cipher",
+ sizeof(mi->ssl_cipher)),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_SSL_Key",
+ sizeof(mi->ssl_key)),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Seconds_Behind_Master", 10,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_SSL_Verify_Server_Cert",
+ 3),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Last_IO_Errno", 4,
+ MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Last_IO_Error", 20),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Last_SQL_Errno", 4,
+ MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Last_SQL_Error", 20),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Replicate_Ignore_Server_Ids",
+ FN_REFLEN),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Master_Server_Id", sizeof(ulong),
+ MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_SSL_Crl",
+ sizeof(mi->ssl_crl)),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Master_SSL_Crlpath",
+ sizeof(mi->ssl_crlpath)),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Using_Gtid",
+ sizeof("Current_Pos")-1),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Gtid_IO_Pos", 30),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Replicate_Do_Domain_Ids",
+ FN_REFLEN),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Replicate_Ignore_Domain_Ids",
+ FN_REFLEN),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Parallel_Mode",
+ sizeof("conservative")-1),
+ mem_root);
if (full)
{
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Retried_transactions", 10,
- MYSQL_TYPE_LONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Max_relay_log_size", 10,
- MYSQL_TYPE_LONGLONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Executed_log_entries", 10,
- MYSQL_TYPE_LONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Slave_received_heartbeats", 10,
- MYSQL_TYPE_LONG),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_float(thd, "Slave_heartbeat_period", 0.0, 3, 10),
- thd->mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Gtid_Slave_Pos",
- gtid_pos_length),
- thd->mem_root);
- }
-
- if (protocol->send_result_set_metadata(&field_list,
- Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
- DBUG_RETURN(TRUE);
- DBUG_RETURN(FALSE);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Retried_transactions", 10,
+ MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Max_relay_log_size", 10,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Executed_log_entries", 10,
+ MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Slave_received_heartbeats", 10,
+ MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_float(thd, "Slave_heartbeat_period", 0.0, 3, 10),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Gtid_Slave_Pos",
+ gtid_pos_length),
+ mem_root);
+ }
+ DBUG_VOID_RETURN;
}
+/* Text for Slave_IO_Running */
+static const char *slave_running[]= { "No", "Connecting", "Preparing", "Yes" };
static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
String *gtid_pos)
@@ -2780,9 +2778,7 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
&my_charset_bin);
protocol->store((ulonglong) mi->rli.group_relay_log_pos);
protocol->store(mi->rli.group_master_log_name, &my_charset_bin);
- protocol->store(mi->slave_running == MYSQL_SLAVE_RUN_CONNECT ?
- "Yes" : (mi->slave_running == MYSQL_SLAVE_RUN_NOT_CONNECT ?
- "Connecting" : "No"), &my_charset_bin);
+ protocol->store(slave_running[mi->slave_running], &my_charset_bin);
protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin);
protocol->store(rpl_filter->get_do_db());
protocol->store(rpl_filter->get_ignore_db());
@@ -2825,7 +2821,7 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
Seconds_Behind_Master: if SQL thread is running and I/O thread is
connected, we can compute it otherwise show NULL (i.e. unknown).
*/
- if ((mi->slave_running == MYSQL_SLAVE_RUN_CONNECT) &&
+ if ((mi->slave_running == MYSQL_SLAVE_RUN_READING) &&
mi->rli.slave_running)
{
long time_diff;
@@ -2962,6 +2958,7 @@ bool show_all_master_info(THD* thd)
uint i, elements;
String gtid_pos;
Master_info **tmp;
+ List<Item> field_list;
DBUG_ENTER("show_master_info");
mysql_mutex_assert_owner(&LOCK_active_mi);
@@ -2972,7 +2969,9 @@ bool show_all_master_info(THD* thd)
DBUG_RETURN(TRUE);
}
- if (send_show_master_info_header(thd, 1, gtid_pos.length()))
+ show_master_info_get_fields(thd, &field_list, 1, gtid_pos.length());
+ if (thd->protocol->send_result_set_metadata(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
if (!master_info_index ||
@@ -4128,16 +4127,16 @@ connected:
if (request_dump(thd, mysql, mi, &suppress_warnings))
{
sql_print_error("Failed on request_dump()");
- if (check_io_slave_killed(mi, "Slave I/O thread killed while \
-requesting master dump") ||
- try_to_reconnect(thd, mysql, mi, &retry_count, suppress_warnings,
- reconnect_messages[SLAVE_RECON_ACT_DUMP]))
+ if (check_io_slave_killed(mi, NullS) ||
+ try_to_reconnect(thd, mysql, mi, &retry_count, suppress_warnings,
+ reconnect_messages[SLAVE_RECON_ACT_DUMP]))
goto err;
goto connected;
}
const char *event_buf;
+ mi->slave_running= MYSQL_SLAVE_RUN_READING;
DBUG_ASSERT(mi->last_error().number == 0);
while (!io_slave_killed(mi))
{
@@ -4150,8 +4149,7 @@ requesting master dump") ||
*/
THD_STAGE_INFO(thd, stage_waiting_for_master_to_send_event);
event_len= read_event(mysql, mi, &suppress_warnings);
- if (check_io_slave_killed(mi, "Slave I/O thread killed while \
-reading event"))
+ if (check_io_slave_killed(mi, NullS))
goto err;
if (event_len == packet_error)
@@ -4607,15 +4605,6 @@ pthread_handler_t handle_slave_sql(void *arg)
serial_rgi->gtid_sub_id= 0;
serial_rgi->gtid_pending= false;
- if (mi->using_gtid != Master_info::USE_GTID_NO)
- {
- /*
- We initialize the relay log state from the know starting position.
- It will then be updated as required by GTID and GTID_LIST events found
- while applying events read from relay logs.
- */
- rli->relay_log_state.load(rpl_global_gtid_slave_state);
- }
rli->gtid_skip_flag = GTID_SKIP_NOT;
if (init_relay_log_pos(rli,
rli->group_relay_log_name,
@@ -4886,6 +4875,7 @@ pthread_handler_t handle_slave_sql(void *arg)
}
strmake_buf(rli->group_relay_log_name, ir->name);
rli->group_relay_log_pos= BIN_LOG_HEADER_SIZE;
+ rli->relay_log_state.load(ir->relay_log_state, ir->relay_log_state_count);
}
}
}
diff --git a/sql/slave.h b/sql/slave.h
index a519229fac1..ca89064d773 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -135,11 +135,11 @@ extern const char *relay_log_index;
extern const char *relay_log_basename;
/*
- 3 possible values for Master_info::slave_running and
+ 4 possible values for Master_info::slave_running and
Relay_log_info::slave_running.
- The values 0,1,2 are very important: to keep the diff small, I didn't
- substitute places where we use 0/1 with the newly defined symbols. So don't change
- these values.
+ The values 0,1,2,3 are very important: to keep the diff small, I didn't
+ substitute places where we use 0/1 with the newly defined symbols.
+ So don't change these values.
The same way, code is assuming that in Relay_log_info we use only values
0/1.
I started with using an enum, but
@@ -148,6 +148,7 @@ extern const char *relay_log_basename;
#define MYSQL_SLAVE_NOT_RUN 0
#define MYSQL_SLAVE_RUN_NOT_CONNECT 1
#define MYSQL_SLAVE_RUN_CONNECT 2
+#define MYSQL_SLAVE_RUN_READING 3
#define RPL_LOG_NAME (rli->group_master_log_name[0] ? rli->group_master_log_name :\
"FIRST")
@@ -206,8 +207,11 @@ int mysql_table_dump(THD* thd, const char* db,
int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
Master_info* mi, MYSQL* mysql, bool overwrite);
+void show_master_info_get_fields(THD *thd, List<Item> *field_list,
+ bool full, size_t gtid_pos_length);
bool show_master_info(THD* thd, Master_info* mi, bool full);
bool show_all_master_info(THD* thd);
+void show_binlog_info_get_fields(THD *thd, List<Item> *field_list);
bool show_binlog_info(THD* thd);
bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report,
bool (*pred)(const void *), const void *param);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index ce4ec09bede..d142b2e1f37 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2534,6 +2534,69 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
/**
+ Collect metadata for SHOW CREATE statement for stored routines.
+
+ @param thd Thread context.
+ @param type Stored routine type
+ @param type Stored routine type
+ (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION)
+
+ @return Error status.
+ @retval FALSE on success
+ @retval TRUE on error
+*/
+
+void
+sp_head::show_create_routine_get_fields(THD *thd, int type, List<Item> *fields)
+{
+ const char *col1_caption= type == TYPE_ENUM_PROCEDURE ?
+ "Procedure" : "Function";
+
+ const char *col3_caption= type == TYPE_ENUM_PROCEDURE ?
+ "Create Procedure" : "Create Function";
+
+ MEM_ROOT *mem_root= thd->mem_root;
+
+ /* Send header. */
+
+ fields->push_back(new (mem_root)
+ Item_empty_string(thd, col1_caption, NAME_CHAR_LEN),
+ mem_root);
+ fields->push_back(new (mem_root)
+ Item_empty_string(thd, "sql_mode", 256),
+ mem_root);
+
+ {
+ /*
+ NOTE: SQL statement field must be not less than 1024 in order not to
+ confuse old clients.
+ */
+
+ Item_empty_string *stmt_fld=
+ new (mem_root) Item_empty_string(thd, col3_caption, 1024);
+ stmt_fld->maybe_null= TRUE;
+
+ fields->push_back(stmt_fld, mem_root);
+ }
+
+ fields->push_back(new (mem_root)
+ Item_empty_string(thd, "character_set_client",
+ MY_CS_NAME_SIZE),
+ mem_root);
+
+ fields->push_back(new (mem_root)
+ Item_empty_string(thd, "collation_connection",
+ MY_CS_NAME_SIZE),
+ mem_root);
+
+ fields->push_back(new (mem_root)
+ Item_empty_string(thd, "Database Collation",
+ MY_CS_NAME_SIZE),
+ mem_root);
+}
+
+
+/**
Implement SHOW CREATE statement for stored routines.
@param thd Thread context.
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 4e761c31d5b..9022f954d11 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -337,6 +337,9 @@ public:
bool
execute_procedure(THD *thd, List<Item> *args);
+ static void
+ show_create_routine_get_fields(THD *thd, int type, List<Item> *fields);
+
bool
show_create_routine(THD *thd, int type);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 7d6301cb5b4..6c6c8263449 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -874,6 +874,17 @@ static void free_acl_role(ACL_ROLE *role)
delete_dynamic(&(role->parent_grantee));
}
+static my_bool check_if_exists(THD *, plugin_ref, void *)
+{
+ return TRUE;
+}
+
+static bool has_validation_plugins()
+{
+ return plugin_foreach(NULL, check_if_exists,
+ MariaDB_PASSWORD_VALIDATION_PLUGIN, NULL);
+}
+
struct validation_data { LEX_STRING *user, *password; };
static my_bool do_validate(THD *, plugin_ref plugin, void *arg)
@@ -885,22 +896,27 @@ static my_bool do_validate(THD *, plugin_ref plugin, void *arg)
}
-static bool validate_password(LEX_STRING *user, LEX_STRING *password)
+static bool validate_password(LEX_USER *user)
{
- struct validation_data data= { user, password };
- return plugin_foreach(NULL, do_validate,
- MariaDB_PASSWORD_VALIDATION_PLUGIN, &data);
-}
-
-static my_bool check_if_exists(THD *, plugin_ref, void *)
-{
- return TRUE;
-}
-
-static bool has_validation_plugins()
-{
- return plugin_foreach(NULL, check_if_exists,
- MariaDB_PASSWORD_VALIDATION_PLUGIN, NULL);
+ if (user->pwtext.length || !user->pwhash.length)
+ {
+ struct validation_data data= { &user->user, &user->pwtext };
+ if (plugin_foreach(NULL, do_validate,
+ MariaDB_PASSWORD_VALIDATION_PLUGIN, &data))
+ {
+ my_error(ER_NOT_VALID_PASSWORD, MYF(0));
+ return true;
+ }
+ }
+ else
+ {
+ if (strict_password_validation && has_validation_plugins())
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--strict-password-validation");
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -984,16 +1000,17 @@ static bool fix_user_plugin_ptr(ACL_USER *user)
- if user->plugin is specified, user->auth is the plugin auth data.
- if user->plugin is mysql_native_password or mysql_old_password,
- user->auth if the password hash, and LEX_USER is transformed
+ user->auth is the password hash, and LEX_USER is transformed
to match the next case (that is, user->plugin is cleared).
- if user->plugin is NOT specified, built-in auth is assumed, that is
mysql_native_password or mysql_old_password. In that case,
- user->auth is the password hash. And user->password is the original
- plain-text password. Either one can be set or even both.
+ user->pwhash is the password hash. And user->pwtext is the original
+ plain-text password. Either one can be set or both.
Upon exiting this function:
- - user->password is the password hash, as the mysql.user.password column
+ - user->pwtext is left untouched
+ - user->pwhash is the password hash, as the mysql.user.password column
- user->plugin is the plugin name, as the mysql.user.plugin column
- user->auth is the plugin auth data, as the mysql.user.authentication_string column
*/
@@ -1001,6 +1018,9 @@ static bool fix_lex_user(THD *thd, LEX_USER *user)
{
size_t check_length;
+ DBUG_ASSERT(user->plugin.length || !user->auth.length);
+ DBUG_ASSERT(!(user->plugin.length && (user->pwtext.length || user->pwhash.length)));
+
if (my_strcasecmp(system_charset_info, user->plugin.str,
native_password_plugin_name.str) == 0)
check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
@@ -1011,36 +1031,26 @@ static bool fix_lex_user(THD *thd, LEX_USER *user)
else
if (user->plugin.length)
return false; // nothing else to do
- else
- if (user->auth.length == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
- check_length= 0; // length is valid, no need to re-check
+ else if (thd->variables.old_passwords == 1 ||
+ user->pwhash.length == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+ check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
else
check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
- if (check_length && user->auth.length && user->auth.length != check_length)
+ if (user->plugin.length)
{
- my_error(ER_PASSWD_LENGTH, MYF(0), check_length);
- return true;
+ user->pwhash= user->auth;
+ user->plugin= empty_lex_str;
+ user->auth= empty_lex_str;
}
- if (user->password.length || !user->auth.length)
- {
- if (validate_password(&user->user, &user->password))
- {
- my_error(ER_NOT_VALID_PASSWORD, MYF(0));
- return true;
- }
- }
- else
+ if (user->pwhash.length && user->pwhash.length != check_length)
{
- if (strict_password_validation && has_validation_plugins())
- {
- my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--strict-password-validation");
- return true;
- }
+ my_error(ER_PASSWD_LENGTH, MYF(0), check_length);
+ return true;
}
- if (user->password.length && !user->auth.length)
+ if (user->pwtext.length && !user->pwhash.length)
{
size_t scramble_length;
void (*make_scramble)(char *, const char *, size_t);
@@ -1059,14 +1069,11 @@ static bool fix_lex_user(THD *thd, LEX_USER *user)
char *buff= (char *) thd->alloc(scramble_length + 1);
if (buff == NULL)
return true;
- make_scramble(buff, user->password.str, user->password.length);
- user->auth.str= buff;
- user->auth.length= scramble_length;
+ make_scramble(buff, user->pwtext.str, user->pwtext.length);
+ user->pwhash.str= buff;
+ user->pwhash.length= scramble_length;
}
- user->password= user->auth.length ? user->auth : null_lex_str;
- user->plugin= empty_lex_str;
- user->auth= empty_lex_str;
return false;
}
@@ -2737,7 +2744,8 @@ bool check_change_password(THD *thd, LEX_USER *user)
{
LEX_USER *real_user= get_current_user(thd, user);
- if (fix_and_copy_user(real_user, user, thd))
+ if (fix_and_copy_user(real_user, user, thd) ||
+ validate_password(real_user))
return true;
*user= *real_user;
@@ -2767,7 +2775,7 @@ bool change_password(THD *thd, LEX_USER *user)
const CSET_STRING query_save __attribute__((unused)) = thd->query_string;
DBUG_ENTER("change_password");
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
- user->host.str, user->user.str, user->password.str));
+ user->host.str, user->user.str, user->pwhash.str));
DBUG_ASSERT(user->host.str != 0); // Ensured by parent
/*
@@ -2784,7 +2792,7 @@ bool change_password(THD *thd, LEX_USER *user)
{
query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
safe_str(user->user.str), safe_str(user->host.str),
- safe_str(user->password.str));
+ safe_str(user->pwhash.str));
}
if (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0))
@@ -2812,10 +2820,10 @@ bool change_password(THD *thd, LEX_USER *user)
if (acl_user->plugin.str == native_password_plugin_name.str ||
acl_user->plugin.str == old_password_plugin_name.str)
{
- acl_user->auth_string.str= strmake_root(&acl_memroot, user->password.str, user->password.length);
- acl_user->auth_string.length= user->password.length;
- set_user_salt(acl_user, user->password.str, user->password.length);
- set_user_plugin(acl_user, user->password.length);
+ acl_user->auth_string.str= strmake_root(&acl_memroot, user->pwhash.str, user->pwhash.length);
+ acl_user->auth_string.length= user->pwhash.length;
+ set_user_salt(acl_user, user->pwhash.str, user->pwhash.length);
+ set_user_plugin(acl_user, user->pwhash.length);
}
else
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
@@ -2825,7 +2833,7 @@ bool change_password(THD *thd, LEX_USER *user)
if (update_user_table(thd, tables[USER_TABLE].table,
safe_str(acl_user->host.hostname),
safe_str(acl_user->user.str),
- user->password.str, user->password.length))
+ user->pwhash.str, user->pwhash.length))
{
mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */
goto end;
@@ -3366,17 +3374,18 @@ static int replace_user_table(THD *thd, TABLE *table, LEX_USER &combo,
mysql_mutex_assert_owner(&acl_cache->lock);
- if (combo.password.str && combo.password.str[0])
+ if (combo.pwhash.str && combo.pwhash.str[0])
{
- if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
- combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+ if (combo.pwhash.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
+ combo.pwhash.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
+ DBUG_ASSERT(0);
my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
DBUG_RETURN(-1);
}
}
else
- combo.password= empty_lex_str;
+ combo.pwhash= empty_lex_str;
/* if the user table is not up to date, we can't handle role updates */
if (table->s->fields <= ROLE_ASSIGN_COLUMN_IDX && handle_as_role)
@@ -3418,7 +3427,7 @@ static int replace_user_table(THD *thd, TABLE *table, LEX_USER &combo,
see also test_if_create_new_users()
*/
- else if (!combo.password.length && !combo.plugin.length && no_auto_create)
+ else if (!combo.pwhash.length && !combo.plugin.length && no_auto_create)
{
my_error(ER_PASSWORD_NO_MATCH, MYF(0));
goto end;
@@ -3450,6 +3459,10 @@ static int replace_user_table(THD *thd, TABLE *table, LEX_USER &combo,
store_record(table,record[1]); // Save copy for update
}
+ if (!old_row_exists || combo.pwtext.length || combo.pwhash.length)
+ if (validate_password(&combo))
+ goto end;
+
/* Update table columns with new privileges */
Field **tmp_field;
@@ -3465,8 +3478,8 @@ static int replace_user_table(THD *thd, TABLE *table, LEX_USER &combo,
}
rights= get_access(table, 3, &next_field);
DBUG_PRINT("info",("table fields: %d",table->s->fields));
- if (combo.password.str[0])
- table->field[2]->store(combo.password.str, combo.password.length, system_charset_info);
+ if (combo.pwhash.str[0])
+ table->field[2]->store(combo.pwhash.str, combo.pwhash.length, system_charset_info);
if (table->s->fields >= 31) /* From 4.0.0 we have more fields */
{
/* We write down SSL related ACL stuff */
@@ -3529,14 +3542,14 @@ static int replace_user_table(THD *thd, TABLE *table, LEX_USER &combo,
table->field[next_field + 1]->set_notnull();
if (combo.plugin.str[0])
{
- DBUG_ASSERT(combo.password.str[0] == 0);
+ DBUG_ASSERT(combo.pwhash.str[0] == 0);
table->field[2]->reset();
table->field[next_field]->store(combo.plugin.str, combo.plugin.length,
system_charset_info);
table->field[next_field + 1]->store(combo.auth.str, combo.auth.length,
system_charset_info);
}
- if (combo.password.str[0])
+ if (combo.pwhash.str[0])
{
DBUG_ASSERT(combo.plugin.str[0] == 0);
table->field[next_field]->reset();
@@ -3605,7 +3618,7 @@ end:
acl_update_role(combo.user.str, rights);
else
acl_update_user(combo.user.str, combo.host.str,
- combo.password.str, combo.password.length,
+ combo.pwhash.str, combo.pwhash.length,
lex->ssl_type,
lex->ssl_cipher,
lex->x509_issuer,
@@ -3621,7 +3634,7 @@ end:
acl_insert_role(combo.user.str, rights);
else
acl_insert_user(combo.user.str, combo.host.str,
- combo.password.str, combo.password.length,
+ combo.pwhash.str, combo.pwhash.length,
lex->ssl_type,
lex->ssl_cipher,
lex->x509_issuer,
@@ -5679,7 +5692,7 @@ static bool merge_one_role_privileges(ACL_ROLE *grantee)
static bool has_auth(LEX_USER *user, LEX *lex)
{
- return user->password.str || user->plugin.length || user->auth.length ||
+ return user->pwtext.length || user->pwhash.length || user->plugin.length || user->auth.length ||
lex->ssl_type != SSL_TYPE_NOT_SPECIFIED || lex->ssl_cipher ||
lex->x509_issuer || lex->x509_subject ||
lex->mqh.specified_limits;
@@ -5690,7 +5703,8 @@ static bool fix_and_copy_user(LEX_USER *to, LEX_USER *from, THD *thd)
if (to != from)
{
/* preserve authentication information, if LEX_USER was reallocated */
- to->password= from->password;
+ to->pwtext= from->pwtext;
+ to->pwhash= from->pwhash;
to->plugin= from->plugin;
to->auth= from->auth;
}
@@ -7723,6 +7737,16 @@ static int show_grants_callback(ACL_USER_BASE *role, void *data)
}
+void mysql_show_grants_get_fields(THD *thd, List<Item> *fields,
+ const char *name)
+{
+ Item_string *field=new (thd->mem_root) Item_string_ascii(thd, "", 0);
+ field->name= (char *) name;
+ field->max_length=1024;
+ fields->push_back(field, thd->mem_root);
+}
+
+
/*
SHOW GRANTS; Send grants for a user to the client
@@ -7788,15 +7812,14 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user)
}
DBUG_ASSERT(rolename || username);
- Item_string *field=new (thd->mem_root) Item_string_ascii(thd, "", 0);
List<Item> field_list;
- field->name=buff;
- field->max_length=1024;
if (!username)
strxmov(buff,"Grants for ",rolename, NullS);
else
strxmov(buff,"Grants for ",username,"@",hostname, NullS);
- field_list.push_back(field, thd->mem_root);
+
+ mysql_show_grants_get_fields(thd, &field_list, buff);
+
if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF))
@@ -10153,15 +10176,11 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
thd->make_lex_string(&combo->user, combo->user.str, strlen(combo->user.str));
thd->make_lex_string(&combo->host, combo->host.str, strlen(combo->host.str));
- combo->password= null_lex_str;
- combo->plugin= empty_lex_str;
- combo->auth= empty_lex_str;
+ combo->reset_auth();
if(au)
{
- if (au->plugin.str != native_password_plugin_name.str &&
- au->plugin.str != old_password_plugin_name.str)
- combo->plugin= au->plugin;
+ combo->plugin= au->plugin;
combo->auth= au->auth_string;
}
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 335a558cddb..0893504b72d 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -241,6 +241,8 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table);
ulong get_column_grant(THD *thd, GRANT_INFO *grant,
const char *db_name, const char *table_name,
const char *field_name);
+void mysql_show_grants_get_fields(THD *thd, List<Item> *fields,
+ const char *name);
bool mysql_show_grants(THD *thd, LEX_USER *user);
int fill_schema_enabled_roles(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_applicable_roles(THD *thd, TABLE_LIST *tables, COND *cond);
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 0787aa9e92f..d8ca8633baa 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -692,10 +692,20 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
}
if (!lex->column_list)
- {
- uint fields= 0;
- for ( ; *field_ptr; field_ptr++, fields++) ;
- bitmap_set_prefix(tab->read_set, fields);
+ {
+ bitmap_clear_all(tab->read_set);
+ for (uint fields= 0; *field_ptr; field_ptr++, fields++)
+ {
+ enum enum_field_types type= (*field_ptr)->type();
+ if (type < MYSQL_TYPE_MEDIUM_BLOB ||
+ type > MYSQL_TYPE_BLOB)
+ bitmap_set_bit(tab->read_set, fields);
+ else
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_NO_EIS_FOR_FIELD,
+ ER_THD(thd, ER_NO_EIS_FOR_FIELD),
+ (*field_ptr)->field_name);
+ }
}
else
{
@@ -713,8 +723,17 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
compl_result_code= result_code= HA_ADMIN_INVALID;
break;
}
- bitmap_set_bit(tab->read_set, pos-1);
- }
+ pos--;
+ enum enum_field_types type= tab->field[pos]->type();
+ if (type < MYSQL_TYPE_MEDIUM_BLOB ||
+ type > MYSQL_TYPE_BLOB)
+ bitmap_set_bit(tab->read_set, pos);
+ else
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_NO_EIS_FOR_FIELD,
+ ER_THD(thd, ER_NO_EIS_FOR_FIELD),
+ column_name->str);
+ }
tab->file->column_bitmaps_signal();
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1ff3625e2db..c8b0092d246 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -8962,6 +8962,9 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
Item *value;
Field *field;
bool abort_on_warning_saved= thd->abort_on_warning;
+ uint autoinc_index= table->next_number_field
+ ? table->next_number_field->field_index
+ : ~0U;
DBUG_ENTER("fill_record");
if (!*ptr)
@@ -8987,7 +8990,7 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
DBUG_ASSERT(field->table == table);
value=v++;
- if (field == table->next_number_field)
+ if (field->field_index == autoinc_index)
table->auto_increment_field_not_null= TRUE;
if (field->vcol_info &&
value->type() != Item::DEFAULT_VALUE_ITEM &&
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index a38822c3f16..345feb6094a 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1817,7 +1817,8 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
void THD::awake(killed_state state_to_set)
{
DBUG_ENTER("THD::awake");
- DBUG_PRINT("enter", ("this: %p current_thd: %p", this, current_thd));
+ DBUG_PRINT("enter", ("this: %p current_thd: %p state: %d",
+ this, current_thd, (int) state_to_set));
THD_CHECK_SENTRY(this);
mysql_mutex_assert_owner(&LOCK_thd_data);
@@ -4024,6 +4025,12 @@ void thd_increment_bytes_sent(void *thd, ulong length)
}
}
+my_bool thd_net_is_killed()
+{
+ THD *thd= current_thd;
+ return thd && thd->killed ? 1 : 0;
+}
+
void thd_increment_bytes_received(void *thd, ulong length)
{
@@ -5158,9 +5165,7 @@ void THD::get_definer(LEX_USER *definer, bool role)
{
definer->user = invoker_user;
definer->host= invoker_host;
- definer->password= null_lex_str;
- definer->plugin= empty_lex_str;
- definer->auth= empty_lex_str;
+ definer->reset_auth();
}
else
#endif
diff --git a/sql/sql_class.h b/sql/sql_class.h
index ffa0a3b887e..a15a738b1bf 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -704,6 +704,7 @@ typedef struct system_status_var
ulong com_stmt_reset;
ulong com_stmt_close;
+ ulong com_register_slave;
ulong created_tmp_disk_tables_;
ulong created_tmp_tables_;
ulong ha_commit_count;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 4548a0bf47c..84f0c6369fd 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1353,6 +1353,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#ifdef HAVE_REPLICATION
case COM_REGISTER_SLAVE:
{
+ status_var_increment(thd->status_var.com_register_slave);
if (!register_slave(thd, (uchar*)packet, packet_length))
my_ok(thd);
break;
@@ -8942,9 +8943,7 @@ void get_default_definer(THD *thd, LEX_USER *definer, bool role)
}
definer->user.length= strlen(definer->user.str);
- definer->password= null_lex_str;
- definer->plugin= empty_lex_str;
- definer->auth= empty_lex_str;
+ definer->reset_auth();
}
@@ -9002,7 +9001,7 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
definer->user= *user_name;
definer->host= *host_name;
- definer->password= null_lex_str;
+ definer->reset_auth();
return definer;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 809e6d63338..ca23e11676a 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -103,6 +103,9 @@ When one supplies long data for a placeholder:
#include "sql_derived.h" // mysql_derived_prepare,
// mysql_handle_derived
#include "sql_cursor.h"
+#include "sql_show.h"
+#include "sql_repl.h"
+#include "slave.h"
#include "sp_head.h"
#include "sp.h"
#include "sp_cache.h"
@@ -1799,6 +1802,191 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
}
+static int send_stmt_metadata(THD *thd, Prepared_statement *stmt, List<Item> *fields)
+{
+ if (stmt->is_sql_prepare())
+ return 0;
+
+ if (send_prep_stmt(stmt, fields->elements) ||
+ thd->protocol->send_result_set_metadata(fields, Protocol::SEND_EOF) ||
+ thd->protocol->flush())
+ return 1;
+
+ return 2;
+}
+
+
+/**
+ Validate and prepare for execution SHOW CREATE TABLE statement.
+
+ @param stmt prepared statement
+ @param tables list of tables used in this query
+
+ @retval
+ FALSE success
+ @retval
+ TRUE error, error message is set in THD
+*/
+
+static int mysql_test_show_create_table(Prepared_statement *stmt,
+ TABLE_LIST *tables)
+{
+ DBUG_ENTER("mysql_test_show_create_table");
+ THD *thd= stmt->thd;
+ List<Item> fields;
+ char buff[2048];
+ String buffer(buff, sizeof(buff), system_charset_info);
+
+ if (mysqld_show_create_get_fields(thd, tables, &fields, &buffer))
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
+}
+
+
+/**
+ Validate and prepare for execution SHOW CREATE DATABASE statement.
+
+ @param stmt prepared statement
+
+ @retval
+ FALSE success
+ @retval
+ TRUE error, error message is set in THD
+*/
+
+static int mysql_test_show_create_db(Prepared_statement *stmt)
+{
+ DBUG_ENTER("mysql_test_show_create_db");
+ THD *thd= stmt->thd;
+ List<Item> fields;
+
+ mysqld_show_create_db_get_fields(thd, &fields);
+
+ DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
+}
+
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+/**
+ Validate and prepare for execution SHOW GRANTS statement.
+
+ @param stmt prepared statement
+
+ @retval
+ FALSE success
+ @retval
+ TRUE error, error message is set in THD
+*/
+
+static int mysql_test_show_grants(Prepared_statement *stmt)
+{
+ DBUG_ENTER("mysql_test_show_grants");
+ THD *thd= stmt->thd;
+ List<Item> fields;
+
+ mysql_show_grants_get_fields(thd, &fields, "Grants for");
+
+ DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
+}
+#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
+
+
+#ifndef EMBEDDED_LIBRARY
+/**
+ Validate and prepare for execution SHOW SLAVE STATUS statement.
+
+ @param stmt prepared statement
+
+ @retval
+ FALSE success
+ @retval
+ TRUE error, error message is set in THD
+*/
+
+static int mysql_test_show_slave_status(Prepared_statement *stmt)
+{
+ DBUG_ENTER("mysql_test_show_slave_status");
+ THD *thd= stmt->thd;
+ List<Item> fields;
+
+ show_master_info_get_fields(thd, &fields, 0, 0);
+
+ DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
+}
+
+
+/**
+ Validate and prepare for execution SHOW MASTER STATUS statement.
+
+ @param stmt prepared statement
+
+ @retval
+ FALSE success
+ @retval
+ TRUE error, error message is set in THD
+*/
+
+static int mysql_test_show_master_status(Prepared_statement *stmt)
+{
+ DBUG_ENTER("mysql_test_show_master_status");
+ THD *thd= stmt->thd;
+ List<Item> fields;
+
+ show_binlog_info_get_fields(thd, &fields);
+
+ DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
+}
+
+
+/**
+ Validate and prepare for execution SHOW BINLOGS statement.
+
+ @param stmt prepared statement
+
+ @retval
+ FALSE success
+ @retval
+ TRUE error, error message is set in THD
+*/
+
+static int mysql_test_show_binlogs(Prepared_statement *stmt)
+{
+ DBUG_ENTER("mysql_test_show_binlogs");
+ THD *thd= stmt->thd;
+ List<Item> fields;
+
+ show_binlogs_get_fields(thd, &fields);
+
+ DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
+}
+
+#endif /* EMBEDDED_LIBRARY */
+
+
+/**
+ Validate and prepare for execution SHOW CREATE PROC/FUNC statement.
+
+ @param stmt prepared statement
+
+ @retval
+ FALSE success
+ @retval
+ TRUE error, error message is set in THD
+*/
+
+static int mysql_test_show_create_routine(Prepared_statement *stmt, int type)
+{
+ DBUG_ENTER("mysql_test_show_binlogs");
+ THD *thd= stmt->thd;
+ List<Item> fields;
+
+ sp_head::show_create_routine_get_fields(thd, type, &fields);
+
+ DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
+}
+
+
/**
@brief Validate and prepare for execution CREATE VIEW statement
@@ -2132,7 +2320,66 @@ static bool check_prepared_statement(Prepared_statement *stmt)
case SQLCOM_CREATE_TABLE:
res= mysql_test_create_table(stmt);
break;
-
+ case SQLCOM_SHOW_CREATE:
+ if ((res= mysql_test_show_create_table(stmt, tables)) == 2)
+ {
+ /* Statement and field info has already been sent */
+ DBUG_RETURN(FALSE);
+ }
+ break;
+ case SQLCOM_SHOW_CREATE_DB:
+ if ((res= mysql_test_show_create_db(stmt)) == 2)
+ {
+ /* Statement and field info has already been sent */
+ DBUG_RETURN(FALSE);
+ }
+ break;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ case SQLCOM_SHOW_GRANTS:
+ if ((res= mysql_test_show_grants(stmt)) == 2)
+ {
+ /* Statement and field info has already been sent */
+ DBUG_RETURN(FALSE);
+ }
+ break;
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+#ifndef EMBEDDED_LIBRARY
+ case SQLCOM_SHOW_SLAVE_STAT:
+ if ((res= mysql_test_show_slave_status(stmt)) == 2)
+ {
+ /* Statement and field info has already been sent */
+ DBUG_RETURN(FALSE);
+ }
+ break;
+ case SQLCOM_SHOW_MASTER_STAT:
+ if ((res= mysql_test_show_master_status(stmt)) == 2)
+ {
+ /* Statement and field info has already been sent */
+ DBUG_RETURN(FALSE);
+ }
+ break;
+ case SQLCOM_SHOW_BINLOGS:
+ if ((res= mysql_test_show_binlogs(stmt)) == 2)
+ {
+ /* Statement and field info has already been sent */
+ DBUG_RETURN(FALSE);
+ }
+ break;
+#endif /* EMBEDDED_LIBRARY */
+ case SQLCOM_SHOW_CREATE_PROC:
+ if ((res= mysql_test_show_create_routine(stmt, TYPE_ENUM_PROCEDURE)) == 2)
+ {
+ /* Statement and field info has already been sent */
+ DBUG_RETURN(FALSE);
+ }
+ break;
+ case SQLCOM_SHOW_CREATE_FUNC:
+ if ((res= mysql_test_show_create_routine(stmt, TYPE_ENUM_FUNCTION)) == 2)
+ {
+ /* Statement and field info has already been sent */
+ DBUG_RETURN(FALSE);
+ }
+ break;
case SQLCOM_CREATE_VIEW:
if (lex->create_view_mode == VIEW_ALTER)
{
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index e524153ad15..19f7e5ab4e6 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -4088,6 +4088,25 @@ err:
}
+void show_binlog_info_get_fields(THD *thd, List<Item> *field_list)
+{
+ MEM_ROOT *mem_root= thd->mem_root;
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "File", FN_REFLEN),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Position", 20,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Binlog_Do_DB", 255),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Binlog_Ignore_DB", 255),
+ mem_root);
+}
+
+
/**
Execute a SHOW MASTER STATUS statement.
@@ -4100,23 +4119,10 @@ err:
bool show_binlog_info(THD* thd)
{
Protocol *protocol= thd->protocol;
- MEM_ROOT *mem_root= thd->mem_root;
DBUG_ENTER("show_binlog_info");
List<Item> field_list;
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "File", FN_REFLEN),
- mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "Position", 20,
- MYSQL_TYPE_LONGLONG),
- mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Binlog_Do_DB", 255),
- mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Binlog_Ignore_DB", 255),
- mem_root);
+ show_binlog_info_get_fields(thd, &field_list);
if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
@@ -4140,6 +4146,19 @@ bool show_binlog_info(THD* thd)
}
+void show_binlogs_get_fields(THD *thd, List<Item> *field_list)
+{
+ MEM_ROOT *mem_root= thd->mem_root;
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Log_name", 255),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "File_size", 20,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+}
+
+
/**
Execute a SHOW BINARY LOGS statement.
@@ -4159,7 +4178,6 @@ bool show_binlogs(THD* thd)
uint length;
int cur_dir_len;
Protocol *protocol= thd->protocol;
- MEM_ROOT *mem_root= thd->mem_root;
DBUG_ENTER("show_binlogs");
if (!mysql_bin_log.is_open())
@@ -4168,13 +4186,8 @@ bool show_binlogs(THD* thd)
DBUG_RETURN(TRUE);
}
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Log_name", 255),
- mem_root);
- field_list.push_back(new (mem_root)
- Item_return_int(thd, "File_size", 20,
- MYSQL_TYPE_LONGLONG),
- mem_root);
+ show_binlogs_get_fields(thd, &field_list);
+
if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(TRUE);
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index 774e43c0a87..e2000bbca73 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -52,6 +52,7 @@ bool purge_master_logs(THD* thd, const char* to_log);
bool purge_master_logs_before_date(THD* thd, time_t purge_time);
bool log_in_use(const char* log_name);
void adjust_linfo_offsets(my_off_t purge_offset);
+void show_binlogs_get_fields(THD *thd, List<Item> *field_list);
bool show_binlogs(THD* thd);
extern int init_master_info(Master_info* mi);
void kill_zombie_dump_threads(uint32 slave_server_id);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index efc710509e7..cb0f9e594ff 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -20633,7 +20633,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT)
- ref_key= -1;
+ {
+ /*
+ we set ref_key=MAX_KEY instead of -1, because test_if_cheaper ordering
+ assumes that "ref_key==-1" means doing full index scan.
+ (This is not very straightforward and we got into this situation for
+ historical reasons. Should be fixed at some point).
+ */
+ ref_key= MAX_KEY;
+ }
else
{
ref_key= select->quick->index;
@@ -25298,8 +25306,12 @@ static bool get_range_limit_read_cost(const JOIN_TAB *tab,
@param table Table if tab == NULL or tab->table
@param usable_keys Key map to find a cheaper key in
@param ref_key
- * 0 <= key < MAX_KEY - key number (hint) to start the search
- * -1 - no key number provided
+ 0 <= key < MAX_KEY - Key that is currently used for finding
+ row
+ MAX_KEY - means index_merge is used
+ -1 - means we're currently not using an
+ index to find rows.
+
@param select_limit LIMIT value
@param [out] new_key Key number if success, otherwise undefined
@param [out] new_key_direction Return -1 (reverse) or +1 if success,
@@ -25328,7 +25340,6 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
uint *saved_best_key_parts)
{
DBUG_ENTER("test_if_cheaper_ordering");
- DBUG_ASSERT(ref_key < int(MAX_KEY));
/*
Check whether there is an index compatible with the given order
usage of which is cheaper than usage of the ref_key index (ref_key>=0)
@@ -25393,7 +25404,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
Calculate the selectivity of the ref_key for REF_ACCESS. For
RANGE_ACCESS we use table->quick_condition_rows.
*/
- if (ref_key >= 0 && !is_hash_join_key_no(ref_key) && tab->type == JT_REF)
+ if (ref_key >= 0 && ref_key != MAX_KEY && tab->type == JT_REF)
{
if (table->quick_keys.is_set(ref_key))
refkey_rows_estimate= table->quick_rows[ref_key];
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 0d2d07a4503..f4dd24a1d0f 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1092,39 +1092,29 @@ public:
/*
- Return CREATE command for table or view
+ Return metadata for CREATE command for table or view
@param thd Thread handler
@param table_list Table / view
+ @param field_list resulting list of fields
+ @param buffer resulting CREATE statement
@return
@retval 0 OK
@retval 1 Error
- @notes
- table_list->db and table_list->table_name are kept unchanged to
- not cause problems with SP.
*/
bool
-mysqld_show_create(THD *thd, TABLE_LIST *table_list)
+mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list,
+ List<Item> *field_list, String *buffer)
{
- Protocol *protocol= thd->protocol;
- char buff[2048];
- String buffer(buff, sizeof(buff), system_charset_info);
- List<Item> field_list;
bool error= TRUE;
MEM_ROOT *mem_root= thd->mem_root;
- DBUG_ENTER("mysqld_show_create");
+ DBUG_ENTER("mysqld_show_create_get_fields");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->table_name));
- /*
- Metadata locks taken during SHOW CREATE should be released when
- the statmement completes as it is an information statement.
- */
- MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
-
/* We want to preserve the tree for views. */
thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
@@ -1155,45 +1145,88 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
goto exit;
}
- buffer.length(0);
+ buffer->length(0);
if (table_list->view)
- buffer.set_charset(table_list->view_creation_ctx->get_client_cs());
+ buffer->set_charset(table_list->view_creation_ctx->get_client_cs());
if ((table_list->view ?
- show_create_view(thd, table_list, &buffer) :
- show_create_table(thd, table_list, &buffer, NULL, WITHOUT_DB_NAME)))
+ show_create_view(thd, table_list, buffer) :
+ show_create_table(thd, table_list, buffer, NULL, WITHOUT_DB_NAME)))
goto exit;
if (table_list->view)
{
- field_list.push_back(new (mem_root)
+ field_list->push_back(new (mem_root)
Item_empty_string(thd, "View", NAME_CHAR_LEN),
mem_root);
- field_list.push_back(new (mem_root)
+ field_list->push_back(new (mem_root)
Item_empty_string(thd, "Create View",
- MY_MAX(buffer.length(),1024)),
+ MY_MAX(buffer->length(),1024)),
mem_root);
- field_list.push_back(new (mem_root)
+ field_list->push_back(new (mem_root)
Item_empty_string(thd, "character_set_client",
MY_CS_NAME_SIZE),
mem_root);
- field_list.push_back(new (mem_root)
+ field_list->push_back(new (mem_root)
Item_empty_string(thd, "collation_connection",
MY_CS_NAME_SIZE),
mem_root);
}
else
{
- field_list.push_back(new (mem_root)
+ field_list->push_back(new (mem_root)
Item_empty_string(thd, "Table", NAME_CHAR_LEN),
mem_root);
// 1024 is for not to confuse old clients
- field_list.push_back(new (mem_root)
+ field_list->push_back(new (mem_root)
Item_empty_string(thd, "Create Table",
- MY_MAX(buffer.length(),1024)),
+ MY_MAX(buffer->length(),1024)),
mem_root);
}
+ error= FALSE;
+
+exit:
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Return CREATE command for table or view
+
+ @param thd Thread handler
+ @param table_list Table / view
+
+ @return
+ @retval 0 OK
+ @retval 1 Error
+
+ @notes
+ table_list->db and table_list->table_name are kept unchanged to
+ not cause problems with SP.
+*/
+
+bool
+mysqld_show_create(THD *thd, TABLE_LIST *table_list)
+{
+ Protocol *protocol= thd->protocol;
+ char buff[2048];
+ String buffer(buff, sizeof(buff), system_charset_info);
+ List<Item> field_list;
+ bool error= TRUE;
+ DBUG_ENTER("mysqld_show_create");
+ DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
+ table_list->table_name));
+
+ /*
+ Metadata locks taken during SHOW CREATE should be released when
+ the statmement completes as it is an information statement.
+ */
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
+
+
+ if (mysqld_show_create_get_fields(thd, table_list, &field_list, &buffer))
+ goto exit;
if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS |
@@ -1239,6 +1272,19 @@ exit:
DBUG_RETURN(error);
}
+
+void mysqld_show_create_db_get_fields(THD *thd, List<Item> *field_list)
+{
+ MEM_ROOT *mem_root= thd->mem_root;
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Database", NAME_CHAR_LEN),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Create Database", 1024),
+ mem_root);
+}
+
+
bool mysqld_show_create_db(THD *thd, LEX_STRING *dbname,
LEX_STRING *orig_dbname,
const DDL_options_st &options)
@@ -1251,7 +1297,7 @@ bool mysqld_show_create_db(THD *thd, LEX_STRING *dbname,
#endif
Schema_specification_st create;
Protocol *protocol=thd->protocol;
- MEM_ROOT *mem_root= thd->mem_root;
+ List<Item> field_list;
DBUG_ENTER("mysql_show_create_db");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1285,13 +1331,8 @@ bool mysqld_show_create_db(THD *thd, LEX_STRING *dbname,
load_db_opt_by_name(thd, dbname->str, &create);
}
- List<Item> field_list;
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Database", NAME_CHAR_LEN),
- mem_root);
- field_list.push_back(new (mem_root)
- Item_empty_string(thd, "Create Database", 1024),
- mem_root);
+
+ mysqld_show_create_db_get_fields(thd, &field_list);
if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS |
diff --git a/sql/sql_show.h b/sql/sql_show.h
index 029249f4129..ecb7e9468ea 100644
--- a/sql/sql_show.h
+++ b/sql/sql_show.h
@@ -85,7 +85,10 @@ bool append_identifier(THD *thd, String *packet, const char *name,
uint length);
void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
+bool mysqld_show_create_get_fields(THD *thd, TABLE_LIST *table_list,
+ List<Item> *field_list, String *buffer);
bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
+void mysqld_show_create_db_get_fields(THD *thd, List<Item> *field_list);
bool mysqld_show_create_db(THD *thd, LEX_STRING *db_name,
LEX_STRING *orig_db_name,
const DDL_options_st &options);
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index b14c3afca4b..8cf20e71f55 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -789,12 +789,114 @@ int stringcmp(const String *s,const String *t)
}
+/**
+ Return a string which has the same value with "from" and
+ which is safe to modify, trying to avoid unnecessary allocation
+ and copying when possible.
+
+ @param to Buffer. Must not be a constant string.
+ @param from Some existing value. We'll try to reuse it.
+ Can be a constant or a variable string.
+ @param from_length The total size that will be possibly needed.
+ Note, can be 0.
+
+ Note, in some cases "from" and "to" can point to the same object.
+
+ If "from" is a variable string and its allocated memory is enough
+ to store "from_length" bytes, then "from" is returned as is.
+
+ If "from" is a variable string and its allocated memory is not enough
+ to store "from_length" bytes, then "from" is reallocated and returned.
+
+ Otherwise (if "from" is a constant string, or looks like a constant string),
+ then "to" is reallocated to fit "from_length" bytes, the value is copied
+ from "from" to "to", then "to" is returned.
+*/
String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
{
- if (from->Alloced_length >= from_length)
- return from;
- if ((from->alloced && (from->Alloced_length != 0)) || !to || from == to)
+ DBUG_ASSERT(to);
+ /*
+ If "from" is a constant string, e.g.:
+ SELECT INSERT('', <pos>, <length>, <replacement>);
+ we should not return it. See MDEV-9332.
+
+ The code below detects different string types:
+
+ a. All constant strings have Alloced_length==0 and alloced==false.
+ They point to a static memory array, or a mem_root memory,
+ and should stay untouched until the end of their life cycle.
+ Not safe to reuse.
+
+ b. Some variable string have Alloced_length==0 and alloced==false initially,
+ they are not bound to any char array and allocate space on the first use
+ (and become #d). A typical example of such String is Item::str_value.
+ This type of string could be reused, but there is no a way to distinguish
+ them from the true constant strings (#a).
+ Not safe to reuse.
+
+ c. Some variable strings have Alloced_length>0 and alloced==false.
+ They point to a fixed size writtable char array (typically on stack)
+ initially but can later allocate more space on the heap when the
+ fixed size array is too small (these strings become #d after allocation).
+ Safe to reuse.
+
+ d. Some variable strings have Alloced_length>0 and alloced==true.
+ They already store data on the heap.
+ Safe to reuse.
+
+ e. Some strings can have Alloced_length==0 and alloced==true.
+ This type of strings allocate space on the heap, but then are marked
+ as constant strings using String::mark_as_const().
+ A typical example - the result of a character set conversion
+ of a constant string.
+ Not safe to reuse.
+ */
+ if (from->Alloced_length > 0) // "from" is #c or #d (not a constant)
{
+ if (from->Alloced_length >= from_length)
+ return from; // #c or #d (large enough to store from_length bytes)
+
+ if (from->alloced)
+ {
+ (void) from->realloc(from_length);
+ return from; // #d (reallocated to fit from_length bytes)
+ }
+ /*
+ "from" is of type #c. It currently points to a writtable char array
+ (typically on stack), but is too small for "from_length" bytes.
+ We need to reallocate either "from" or "to".
+
+ "from" typically points to a temporary buffer inside Item_xxx::val_str(),
+ or to Item::str_value, and thus is "less permanent" than "to".
+
+ Reallocating "to" may give more benifits:
+ - "to" can point to a "more permanent" storage and can be reused
+ for multiple rows, e.g. str_buffer in Protocol::send_result_set_row(),
+ which is passed to val_str() for all string type rows.
+ - "from" can stay pointing to its original fixed size stack char array,
+ and thus reduce the total amount of my_alloc/my_free.
+ */
+ }
+
+ if (from == to)
+ {
+ /*
+ Possible string types:
+ #a not possible (constants should not be passed as "to")
+ #b possible (a fresh variable with no associated char buffer)
+ #c possible (a variable with a char buffer,
+ in case it's smaller than fixed_length)
+ #d not possible (handled earlier)
+ #e not possible (constants should not be passed as "to")
+
+ If a string of types #a or #e appears here, that means the caller made
+ something wrong. Otherwise, it's safe to reallocate and return "to".
+
+ Note, as we can't distinguish between #a and #b for sure,
+ so we can't assert "not #a", but we can at least assert "not #e".
+ */
+ DBUG_ASSERT(!from->alloced || from->Alloced_length > 0); // Not #e
+
(void) from->realloc(from_length);
return from;
}
@@ -803,7 +905,7 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
if ((to->str_length=MY_MIN(from->str_length,from_length)))
memcpy(to->Ptr,from->Ptr,to->str_length);
to->str_charset=from->str_charset;
- return to;
+ return to; // "from" was of types #a, #b, #e, or small #c.
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 3eb6a99a131..1899dd60f88 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -248,6 +248,35 @@ static bool maybe_start_compound_statement(THD *thd)
return 0;
}
+static bool push_sp_label(THD *thd, LEX_STRING label)
+{
+ sp_pcontext *ctx= thd->lex->spcont;
+ sp_label *lab= ctx->find_label(label);
+
+ if (lab)
+ {
+ my_error(ER_SP_LABEL_REDEFINE, MYF(0), label.str);
+ return 1;
+ }
+ else
+ {
+ lab= thd->lex->spcont->push_label(thd, label,
+ thd->lex->sphead->instructions());
+ lab->type= sp_label::ITERATION;
+ }
+ return 0;
+}
+
+static bool push_sp_empty_label(THD *thd)
+{
+ if (maybe_start_compound_statement(thd))
+ return 1;
+ /* Unlabeled controls get an empty label. */
+ thd->lex->spcont->push_label(thd, empty_lex_str,
+ thd->lex->sphead->instructions());
+ return 0;
+}
+
/**
Helper action for a case expression statement (the expr in 'CASE expr').
This helper is used for 'searched' cases only.
@@ -1950,6 +1979,7 @@ END_OF_INPUT
%type <NONE> sp_proc_stmt_iterate
%type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close
%type <NONE> case_stmt_specification
+%type <NONE> loop_body while_body repeat_body
%type <num> sp_decl_idents sp_handler_type sp_hcond_list
%type <spcondvalue> sp_cond sp_hcond sqlstate signal_value opt_signal_value
@@ -3751,7 +3781,7 @@ sp_proc_stmt_statement:
if (yychar == YYEMPTY)
i->m_query.length= lip->get_ptr() - sp->m_tmp_query;
else
- i->m_query.length= lip->get_tok_end() - sp->m_tmp_query;
+ i->m_query.length= lip->get_tok_start() - sp->m_tmp_query;;
if (!(i->m_query.str= strmake_root(thd->mem_root,
sp->m_tmp_query,
i->m_query.length)) ||
@@ -3793,20 +3823,6 @@ sp_proc_stmt_return:
}
;
-sp_unlabeled_control:
- {
- if (maybe_start_compound_statement(thd))
- MYSQL_YYABORT;
- /* Unlabeled controls get an empty label. */
- Lex->spcont->push_label(thd, empty_lex_str,
- Lex->sphead->instructions());
- }
- sp_control_content
- {
- Lex->sphead->backpatch(Lex->spcont->pop_label());
- }
- ;
-
sp_proc_stmt_leave:
LEAVE_SYM label_ident
{
@@ -4225,41 +4241,6 @@ else_clause_opt:
| ELSE sp_proc_stmts1
;
-sp_labeled_control:
- label_ident ':'
- {
- LEX *lex= Lex;
- sp_pcontext *ctx= lex->spcont;
- sp_label *lab= ctx->find_label($1);
-
- if (lab)
- {
- my_error(ER_SP_LABEL_REDEFINE, MYF(0), $1.str);
- MYSQL_YYABORT;
- }
- else
- {
- lab= lex->spcont->push_label(thd, $1, lex->sphead->instructions());
- lab->type= sp_label::ITERATION;
- }
- }
- sp_control_content sp_opt_label
- {
- LEX *lex= Lex;
- sp_label *lab= lex->spcont->pop_label();
-
- if ($5.str)
- {
- if (my_strcasecmp(system_charset_info, $5.str, lab->name.str) != 0)
- {
- my_error(ER_SP_LABEL_MISMATCH, MYF(0), $5.str);
- MYSQL_YYABORT;
- }
- }
- lex->sphead->backpatch(lab);
- }
- ;
-
sp_opt_label:
/* Empty */ { $$= null_lex_str; }
| label_ident { $$= $1; }
@@ -4352,8 +4333,7 @@ sp_block_content:
}
;
-sp_control_content:
- LOOP_SYM
+loop_body:
sp_proc_stmts1 END LOOP_SYM
{
LEX *lex= Lex;
@@ -4365,15 +4345,16 @@ sp_control_content:
lex->sphead->add_instr(i))
MYSQL_YYABORT;
}
- | WHILE_SYM
- { Lex->sphead->reset_lex(thd); }
+ ;
+
+while_body:
expr DO_SYM
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
uint ip= sp->instructions();
sp_instr_jump_if_not *i= new (lex->thd->mem_root)
- sp_instr_jump_if_not(ip, lex->spcont, $3, lex);
+ sp_instr_jump_if_not(ip, lex->spcont, $1, lex);
if (i == NULL ||
/* Jumping forward */
sp->push_backpatch(thd, i, lex->spcont->last_label()) ||
@@ -4395,7 +4376,10 @@ sp_control_content:
MYSQL_YYABORT;
lex->sphead->do_cont_backpatch();
}
- | REPEAT_SYM sp_proc_stmts1 UNTIL_SYM
+ ;
+
+repeat_body:
+ sp_proc_stmts1 UNTIL_SYM
{ Lex->sphead->reset_lex(thd); }
expr END REPEAT_SYM
{
@@ -4403,7 +4387,7 @@ sp_control_content:
uint ip= lex->sphead->instructions();
sp_label *lab= lex->spcont->last_label(); /* Jumping back */
sp_instr_jump_if_not *i= new (lex->thd->mem_root)
- sp_instr_jump_if_not(ip, lex->spcont, $5, lab->ip, lex);
+ sp_instr_jump_if_not(ip, lex->spcont, $4, lab->ip, lex);
if (i == NULL ||
lex->sphead->add_instr(i))
MYSQL_YYABORT;
@@ -4414,6 +4398,84 @@ sp_control_content:
}
;
+pop_sp_label:
+ sp_opt_label
+ {
+ sp_label *lab;
+ Lex->sphead->backpatch(lab= Lex->spcont->pop_label());
+ if ($1.str)
+ {
+ if (my_strcasecmp(system_charset_info, $1.str,
+ lab->name.str) != 0)
+ {
+ my_error(ER_SP_LABEL_MISMATCH, MYF(0), $1.str);
+ MYSQL_YYABORT;
+ }
+ }
+ }
+ ;
+
+pop_sp_empty_label:
+ {
+ sp_label *lab;
+ Lex->sphead->backpatch(lab= Lex->spcont->pop_label());
+ DBUG_ASSERT(lab->name.length == 0);
+ }
+ ;
+
+sp_labeled_control:
+ label_ident ':' LOOP_SYM
+ {
+ if (push_sp_label(thd, $1))
+ MYSQL_YYABORT;
+ }
+ loop_body pop_sp_label
+ { }
+ | label_ident ':' WHILE_SYM
+ {
+ if (push_sp_label(thd, $1))
+ MYSQL_YYABORT;
+ Lex->sphead->reset_lex(thd);
+ }
+ while_body pop_sp_label
+ { }
+ | label_ident ':' REPEAT_SYM
+ {
+ if (push_sp_label(thd, $1))
+ MYSQL_YYABORT;
+ }
+ repeat_body pop_sp_label
+ { }
+ ;
+
+sp_unlabeled_control:
+ LOOP_SYM
+ {
+ if (push_sp_empty_label(thd))
+ MYSQL_YYABORT;
+ }
+ loop_body
+ pop_sp_empty_label
+ { }
+ | WHILE_SYM
+ {
+ if (push_sp_empty_label(thd))
+ MYSQL_YYABORT;
+ Lex->sphead->reset_lex(thd);
+ }
+ while_body
+ pop_sp_empty_label
+ { }
+ | REPEAT_SYM
+ {
+ if (push_sp_empty_label(thd))
+ MYSQL_YYABORT;
+ }
+ repeat_body
+ pop_sp_empty_label
+ { }
+ ;
+
trg_action_time:
BEFORE_SYM
{ Lex->trg_chistics.action_time= TRG_ACTION_BEFORE; }
@@ -14080,9 +14142,7 @@ user_maybe_role:
MYSQL_YYABORT;
$$->user = $1;
$$->host= null_lex_str; // User or Role, see get_current_user()
- $$->password= null_lex_str;
- $$->plugin= empty_lex_str;
- $$->auth= empty_lex_str;
+ $$->reset_auth();
if (check_string_char_length(&$$->user, ER_USERNAME,
username_char_length,
@@ -14094,9 +14154,7 @@ user_maybe_role:
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
MYSQL_YYABORT;
$$->user = $1; $$->host=$3;
- $$->password= null_lex_str;
- $$->plugin= empty_lex_str;
- $$->auth= empty_lex_str;
+ $$->reset_auth();
if (check_string_char_length(&$$->user, ER_USERNAME,
username_char_length,
@@ -15012,14 +15070,14 @@ opt_for_user:
;
text_or_password:
- TEXT_STRING { Lex->definer->auth= $1;}
- | PASSWORD_SYM '(' TEXT_STRING ')' { Lex->definer->password= $3; }
+ TEXT_STRING { Lex->definer->pwhash= $1;}
+ | PASSWORD_SYM '(' TEXT_STRING ')' { Lex->definer->pwtext= $3; }
| OLD_PASSWORD_SYM '(' TEXT_STRING ')'
{
- Lex->definer->password= $3;
- Lex->definer->auth.str= Item_func_password::alloc(thd,
+ Lex->definer->pwtext= $3;
+ Lex->definer->pwhash.str= Item_func_password::alloc(thd,
$3.str, $3.length, Item_func_password::OLD);
- Lex->definer->auth.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ Lex->definer->pwhash.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
}
;
@@ -15358,9 +15416,7 @@ current_role:
if (!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER))))
MYSQL_YYABORT;
$$->user= current_role;
- $$->password= null_lex_str;
- $$->plugin= empty_lex_str;
- $$->auth= empty_lex_str;
+ $$->reset_auth();
}
;
@@ -15379,9 +15435,7 @@ grant_role:
MYSQL_YYABORT;
$$->user = $1;
$$->host= empty_lex_str;
- $$->password= null_lex_str;
- $$->plugin= empty_lex_str;
- $$->auth= empty_lex_str;
+ $$->reset_auth();
if (check_string_char_length(&$$->user, ER_USERNAME,
username_char_length,
@@ -15597,14 +15651,15 @@ using_or_as: USING | AS ;
grant_user:
user IDENTIFIED_SYM BY TEXT_STRING
{
- $$=$1; $1->password=$4;
+ $$= $1;
+ $1->pwtext= $4;
if (Lex->sql_command == SQLCOM_REVOKE)
MYSQL_YYABORT;
}
| user IDENTIFIED_SYM BY PASSWORD_SYM TEXT_STRING
{
$$= $1;
- $1->auth= $5;
+ $1->pwhash= $5;
}
| user IDENTIFIED_SYM via_or_with ident_or_text
{
diff --git a/sql/structs.h b/sql/structs.h
index 8dc6323bde0..e51f3e0fe3a 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -202,7 +202,8 @@ extern const char *show_comp_option_name[];
typedef int *(*update_var)(THD *, struct st_mysql_show_var *);
typedef struct st_lex_user {
- LEX_STRING user, host, password, plugin, auth;
+ LEX_STRING user, host, plugin, auth;
+ LEX_STRING pwtext, pwhash;
bool is_role() { return user.str[0] && !host.str[0]; }
void set_lex_string(LEX_STRING *l, char *buf)
{
@@ -211,6 +212,12 @@ typedef struct st_lex_user {
else
l->length= strxmov(l->str= buf, user.str, "@", host.str, NullS) - buf;
}
+ void reset_auth()
+ {
+ pwtext.length= pwhash.length= plugin.length= auth.length= 0;
+ pwtext.str= pwhash.str= 0;
+ plugin.str= auth.str= const_cast<char*>("");
+ }
} LEX_USER;
/*
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 31e0be3cd4d..08f4e3e4ea0 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -4483,6 +4483,28 @@ static bool update_slave_skip_counter(sys_var *self, THD *thd, Master_info *mi)
mi->connection_name.str);
return true;
}
+ if (mi->using_gtid != Master_info::USE_GTID_NO && mi->using_parallel())
+ {
+ ulong domain_count;
+ mysql_mutex_lock(&rpl_global_gtid_slave_state->LOCK_slave_state);
+ domain_count= rpl_global_gtid_slave_state->count();
+ mysql_mutex_unlock(&rpl_global_gtid_slave_state->LOCK_slave_state);
+ if (domain_count > 1)
+ {
+ /*
+ With domain-based parallel replication, the slave position is
+ multi-dimensional, so the relay log position is not very meaningful.
+ It might not even correspond to the next GTID to execute in _any_
+ domain (the case after error stop). So slave_skip_counter will most
+ likely not do what the user intends. Instead give an error, with a
+ suggestion to instead set @@gtid_slave_pos past the point of error;
+ this works reliably also in the case of multiple domains.
+ */
+ my_error(ER_SLAVE_SKIP_NOT_IN_GTID, MYF(0));
+ return true;
+ }
+ }
+
/* The value was stored temporarily in thd */
mi->rli.slave_skip_counter= thd->variables.slave_skip_counter;
return false;
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index b922d2b2857..03524c8ad5c 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -91,12 +91,6 @@ my_bool wsrep_slave_UK_checks = 0; // slave thread does UK checks
my_bool wsrep_slave_FK_checks = 0; // slave thread does FK checks
bool wsrep_new_cluster = false; // Bootstrap the cluster ?
-/*
- Set during the creation of first wsrep applier and rollback threads.
- Since these threads are critical, abort if the thread creation fails.
-*/
-my_bool wsrep_creating_startup_threads = 0;
-
// Use wsrep_gtid_domain_id for galera transactions?
bool wsrep_gtid_mode = 0;
// gtid_domain_id for galera transactions.
@@ -798,7 +792,6 @@ void wsrep_init_startup (bool first)
if (!wsrep_start_replication()) unireg_abort(1);
- wsrep_creating_startup_threads= 1;
wsrep_create_rollbacker();
wsrep_create_appliers(1);
@@ -1820,21 +1813,11 @@ pthread_handler_t start_wsrep_THD(void *arg)
//thd->version= refresh_version;
thd->proc_info= 0;
thd->set_command(COM_SLEEP);
-
- if (wsrep_creating_startup_threads == 0)
- {
- thd->init_for_queries();
- }
+ thd->init_for_queries();
mysql_mutex_lock(&LOCK_thread_count);
wsrep_running_threads++;
mysql_cond_broadcast(&COND_thread_count);
-
- if (wsrep_running_threads > 2)
- {
- wsrep_creating_startup_threads= 0;
- }
-
mysql_mutex_unlock(&LOCK_thread_count);
processor(thd);
@@ -1877,7 +1860,7 @@ error:
WSREP_ERROR("Failed to create/initialize system thread");
/* Abort if its the first applier/rollbacker thread. */
- if (wsrep_creating_startup_threads == 1)
+ if (!mysqld_server_initialized)
unireg_abort(1);
else
return NULL;
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index 26d3484b3b4..a22eb1a0b64 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -86,7 +86,6 @@ extern my_bool wsrep_slave_FK_checks;
extern my_bool wsrep_slave_UK_checks;
extern ulong wsrep_running_threads;
extern bool wsrep_new_cluster;
-extern my_bool wsrep_creating_startup_threads;
extern bool wsrep_gtid_mode;
extern uint32 wsrep_gtid_domain_id;
@@ -341,7 +340,6 @@ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len);
#define wsrep_thr_init() do {} while(0)
#define wsrep_thr_deinit() do {} while(0)
#define wsrep_running_threads (0)
-#define wsrep_creating_startup_threads (0)
#endif /* WITH_WSREP */
#endif /* WSREP_MYSQLD_H */
diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc
index ab09a9e3a99..fb48c1ad60e 100644
--- a/sql/wsrep_thd.cc
+++ b/sql/wsrep_thd.cc
@@ -369,6 +369,25 @@ static void wsrep_replication_process(THD *thd)
DBUG_VOID_RETURN;
}
+static bool create_wsrep_THD(wsrep_thd_processor_fun processor)
+{
+ ulong old_wsrep_running_threads= wsrep_running_threads;
+ pthread_t unused;
+ mysql_mutex_lock(&LOCK_thread_count);
+ bool res= pthread_create(&unused, &connection_attrib, start_wsrep_THD,
+ (void*)processor);
+ /*
+ if starting a thread on server startup, wait until the this thread's THD
+ is fully initialized (otherwise a THD initialization code might
+ try to access a partially initialized server data structure - MDEV-8208).
+ */
+ if (!mysqld_server_initialized)
+ while (old_wsrep_running_threads == wsrep_running_threads)
+ mysql_cond_wait(&COND_thread_count, &LOCK_thread_count);
+ mysql_mutex_unlock(&LOCK_thread_count);
+ return res;
+}
+
void wsrep_create_appliers(long threads)
{
if (!wsrep_connected)
@@ -385,11 +404,8 @@ void wsrep_create_appliers(long threads)
}
long wsrep_threads=0;
- pthread_t hThread;
while (wsrep_threads++ < threads) {
- if (pthread_create(
- &hThread, &connection_attrib,
- start_wsrep_THD, (void*)wsrep_replication_process))
+ if (create_wsrep_THD(wsrep_replication_process))
WSREP_WARN("Can't create thread to manage wsrep replication");
}
}
@@ -476,10 +492,8 @@ void wsrep_create_rollbacker()
{
if (wsrep_provider && strcasecmp(wsrep_provider, "none"))
{
- pthread_t hThread;
/* create rollbacker */
- if (pthread_create( &hThread, &connection_attrib,
- start_wsrep_THD, (void*)wsrep_rollback_process))
+ if (create_wsrep_THD(wsrep_rollback_process))
WSREP_WARN("Can't create thread to manage wsrep rollback");
}
}