summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2022-05-03 10:59:54 +0200
committerOleksandr Byelkin <sanja@mariadb.com>2022-05-03 10:59:54 +0200
commit9614fde1aac6ffa4745804342ff70a96b2418e30 (patch)
treed53f4578ce0a6b5cf30f3eef854d50c16fbabcee /sql
parent182b8a29e7a1a0f0fbffeed39518c2c9dc026e13 (diff)
parent70555454b4c224e85383d482411961c7f2eba2e2 (diff)
downloadmariadb-git-9614fde1aac6ffa4745804342ff70a96b2418e30.tar.gz
Merge branch '10.2' into 10.3
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc17
-rw-r--r--sql/field.h2
-rw-r--r--sql/handler.cc3
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_subselect.cc26
-rw-r--r--sql/item_sum.cc6
-rw-r--r--sql/rpl_gtid.h1
-rw-r--r--sql/slave.cc165
-rw-r--r--sql/sp_cache.cc9
-rw-r--r--sql/sp_head.cc2
-rw-r--r--sql/sql_class.cc15
-rw-r--r--sql/sql_class.h40
-rw-r--r--sql/sql_expression_cache.cc4
-rw-r--r--sql/sql_expression_cache.h5
-rw-r--r--sql/sql_handler.cc4
-rw-r--r--sql/sql_select.cc4
-rw-r--r--sql/sql_show.cc32
-rw-r--r--sql/sql_type.cc1
-rw-r--r--sql/sql_yacc.yy16
-rw-r--r--sql/sql_yacc_ora.yy16
-rw-r--r--sql/table.cc2
-rw-r--r--sql/tztime.cc8
22 files changed, 307 insertions, 73 deletions
diff --git a/sql/field.cc b/sql/field.cc
index be9c10a3bae..57cf3deed35 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -3116,6 +3116,15 @@ Field *Field_decimal::make_new_field(MEM_ROOT *root, TABLE *new_table,
}
+void Field_new_decimal::set_and_validate_prec(uint32 len_arg,
+ uint8 dec_arg, bool unsigned_arg)
+{
+ precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
+ set_if_smaller(precision, DECIMAL_MAX_PRECISION);
+ bin_size= my_decimal_get_binary_size(precision, dec);
+}
+
+
/****************************************************************************
** Field_new_decimal
****************************************************************************/
@@ -3134,12 +3143,10 @@ Field_new_decimal::Field_new_decimal(uchar *ptr_arg,
uint8 dec_arg,bool zero_arg,
bool unsigned_arg)
:Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg)
+ unireg_check_arg, field_name_arg,
+ MY_MIN(dec_arg, DECIMAL_MAX_SCALE), zero_arg, unsigned_arg)
{
- precision= get_decimal_precision(len_arg, dec_arg, unsigned_arg);
- DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) &&
- (dec <= DECIMAL_MAX_SCALE));
- bin_size= my_decimal_get_binary_size(precision, dec);
+ set_and_validate_prec(len_arg, dec_arg, unsigned_arg);
}
diff --git a/sql/field.h b/sql/field.h
index 41bed111f50..4ef4483a15a 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1984,6 +1984,8 @@ public:
class Field_new_decimal :public Field_num {
private:
int save_field_metadata(uchar *first_byte);
+ void set_and_validate_prec(uint32 len_arg,
+ uint8 dec_arg, bool unsigned_arg);
public:
/* The maximum number of decimal digits can be stored */
uint precision;
diff --git a/sql/handler.cc b/sql/handler.cc
index e4c377451c6..2048ce137da 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -5118,6 +5118,9 @@ int handler::calculate_checksum()
for (uint i= 0; i < table->s->fields; i++ )
{
Field *f= table->field[i];
+ if (!f->stored_in_db())
+ continue;
+
if (! thd->variables.old_mode && f->is_real_null(0))
{
diff --git a/sql/item_func.cc b/sql/item_func.cc
index b8355a38701..3fd69405456 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2463,7 +2463,7 @@ void Item_func_round::fix_arg_decimal()
set_handler(&type_handler_newdecimal);
unsigned_flag= args[0]->unsigned_flag;
decimals= args[0]->decimals;
- max_length= float_length(args[0]->decimals) + 1;
+ max_length= args[0]->max_length;
}
}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 88db52db13d..2e33a71b8f9 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -763,6 +763,7 @@ bool Item_subselect::exec()
DBUG_ENTER("Item_subselect::exec");
DBUG_ASSERT(fixed);
+ DBUG_ASSERT(!eliminated);
DBUG_EXECUTE_IF("Item_subselect",
Item::Print print(this,
@@ -1272,11 +1273,18 @@ bool Item_singlerow_subselect::fix_length_and_dec()
}
unsigned_flag= value->unsigned_flag;
/*
- If there are not tables in subquery then ability to have NULL value
- depends on SELECT list (if single row subquery have tables then it
- always can be NULL if there are not records fetched).
+ If the subquery has no tables (1) and is not a UNION (2), like:
+
+ (SELECT subq_value)
+
+ then its NULLability is the same as subq_value's NULLability.
+
+ (1): A subquery that uses a table will return NULL when the table is empty.
+ (2): A UNION subquery will return NULL if it produces a "Subquery returns
+ more than one row" error.
*/
- if (engine->no_tables())
+ if (engine->no_tables() &&
+ engine->engine_type() != subselect_engine::UNION_ENGINE)
maybe_null= engine->may_be_null();
else
{
@@ -1312,6 +1320,16 @@ Item* Item_singlerow_subselect::expr_cache_insert_transformer(THD *tmp_thd,
DBUG_ASSERT(thd == tmp_thd);
+ /*
+ Do not create subquery cache if the subquery was eliminated.
+ The optimizer may eliminate subquery items (see
+ eliminate_subselect_processor). However it does not update
+ all query's data structures, so the eliminated item may be
+ still reachable.
+ */
+ if (eliminated)
+ DBUG_RETURN(this);
+
if (expr_cache)
DBUG_RETURN(expr_cache);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 4c6c3258d11..72e01a1e0e4 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1539,6 +1539,8 @@ void Item_sum_sum::fix_length_and_dec_decimal()
decimals= args[0]->decimals;
/* SUM result can't be longer than length(arg) + length(MAX_ROWS) */
int precision= args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS;
+ decimals= MY_MIN(decimals, DECIMAL_MAX_SCALE);
+ precision= MY_MIN(precision, DECIMAL_MAX_PRECISION);
max_length= my_decimal_precision_to_length_no_truncation(precision,
decimals,
unsigned_flag);
@@ -1954,12 +1956,12 @@ void Item_sum_avg::fix_length_and_dec_decimal()
{
Item_sum_sum::fix_length_and_dec_decimal();
int precision= args[0]->decimal_precision() + prec_increment;
- decimals= MY_MIN(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
+ decimals= MY_MIN(args[0]->decimal_scale() + prec_increment, DECIMAL_MAX_SCALE);
max_length= my_decimal_precision_to_length_no_truncation(precision,
decimals,
unsigned_flag);
f_precision= MY_MIN(precision+DECIMAL_LONGLONG_DIGITS, DECIMAL_MAX_PRECISION);
- f_scale= args[0]->decimals;
+ f_scale= args[0]->decimal_scale();
dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale);
}
diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h
index b3341b20165..fec0cccdb0a 100644
--- a/sql/rpl_gtid.h
+++ b/sql/rpl_gtid.h
@@ -26,6 +26,7 @@
extern const LEX_CSTRING rpl_gtid_slave_state_table_name;
class String;
+#define PARAM_GTID(G) G.domain_id, G.server_id, G.seq_no
struct rpl_gtid
{
diff --git a/sql/slave.cc b/sql/slave.cc
index f64ab0d015f..0ecba3c42b8 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3214,9 +3214,9 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
protocol->store((uint32) mi->master_id);
// SQL_Delay
// Master_Ssl_Crl
- protocol->store(mi->ssl_ca, &my_charset_bin);
+ protocol->store(mi->ssl_crl, &my_charset_bin);
// Master_Ssl_Crlpath
- protocol->store(mi->ssl_capath, &my_charset_bin);
+ protocol->store(mi->ssl_crlpath, &my_charset_bin);
// Using_Gtid
protocol->store(mi->using_gtid_astext(mi->using_gtid), &my_charset_bin);
// Gtid_IO_Pos
@@ -3315,7 +3315,7 @@ bool show_all_master_info(THD* thd)
String gtid_pos;
Master_info **tmp;
List<Item> field_list;
- DBUG_ENTER("show_master_info");
+ DBUG_ENTER("show_all_master_info");
mysql_mutex_assert_owner(&LOCK_active_mi);
gtid_pos.length(0);
@@ -6573,17 +6573,75 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
mi->gtid_event_seen= true;
/*
- We have successfully queued to relay log everything before this GTID, so
+ Unless the previous group is malformed,
+ we have successfully queued to relay log everything before this GTID, so
in case of reconnect we can start from after any previous GTID.
- (Normally we would have updated gtid_current_pos earlier at the end of
- the previous event group, but better leave an extra check here for
- safety).
+ (We must have updated gtid_current_pos earlier at the end of
+ the previous event group. Unless ...)
*/
- if (mi->events_queued_since_last_gtid)
+ if (unlikely(mi->events_queued_since_last_gtid > 0))
{
- mi->gtid_current_pos.update(&mi->last_queued_gtid);
- mi->events_queued_since_last_gtid= 0;
+ /*
+ ...unless the last group has not been completed. An assert below
+ can be satisfied only with the strict mode that ensures
+ against "genuine" gtid duplicates.
+ */
+ rpl_gtid *gtid_in_slave_state=
+ mi->gtid_current_pos.find(mi->last_queued_gtid.domain_id);
+
+ // Slave gtid state must not have updated yet to the last received gtid.
+ DBUG_ASSERT((mi->using_gtid == Master_info::USE_GTID_NO ||
+ !opt_gtid_strict_mode) ||
+ (!gtid_in_slave_state ||
+ !(*gtid_in_slave_state == mi->last_queued_gtid)));
+
+ DBUG_EXECUTE_IF("slave_discard_xid_for_gtid_0_x_1000",
+ {
+ /* Inject an event group that is missing its XID commit event. */
+ if ((mi->last_queued_gtid.domain_id == 0 &&
+ mi->last_queued_gtid.seq_no == 1000) ||
+ (mi->last_queued_gtid.domain_id == 1 &&
+ mi->last_queued_gtid.seq_no == 32))
+ {
+ sql_print_warning(
+ "Unexpected break of being relay-logged GTID %u-%u-%llu "
+ "event group by the current GTID event %u-%u-%llu",
+ PARAM_GTID(mi->last_queued_gtid),PARAM_GTID(event_gtid));
+ DBUG_SET("-d,slave_discard_xid_for_gtid_0_x_1000");
+ goto dbug_gtid_accept;
+ }
+ });
+ error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
+ sql_print_error("Unexpected break of being relay-logged GTID %u-%u-%llu "
+ "event group by the current GTID event %u-%u-%llu",
+ PARAM_GTID(mi->last_queued_gtid),PARAM_GTID(event_gtid));
+ goto err;
}
+ else if (unlikely(mi->gtid_reconnect_event_skip_count > 0))
+ {
+ if (mi->gtid_reconnect_event_skip_count ==
+ mi->events_queued_since_last_gtid)
+ {
+ DBUG_ASSERT(event_gtid == mi->last_queued_gtid);
+
+ goto default_action;
+ }
+
+ DBUG_ASSERT(0);
+ }
+ // else_likely{...
+#ifndef DBUG_OFF
+dbug_gtid_accept:
+ DBUG_EXECUTE_IF("slave_discard_gtid_0_x_1002",
+ {
+ if (mi->last_queued_gtid.server_id == 27697 &&
+ mi->last_queued_gtid.seq_no == 1002)
+ {
+ DBUG_SET("-d,slave_discard_gtid_0_x_1002");
+ goto skip_relay_logging;
+ }
+ });
+#endif
mi->last_queued_gtid= event_gtid;
mi->last_queued_gtid_standalone=
(gtid_flag & Gtid_log_event::FL_STANDALONE) != 0;
@@ -6593,6 +6651,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
++mi->events_queued_since_last_gtid;
inc_pos= event_len;
+ // ...} eof else_likely
}
break;
/*
@@ -6671,6 +6730,12 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
case XID_EVENT:
DBUG_EXECUTE_IF("slave_discard_xid_for_gtid_0_x_1000",
{
+ if (mi->last_queued_gtid.server_id == 27697 &&
+ mi->last_queued_gtid.seq_no == 1000)
+ {
+ DBUG_SET("-d,slave_discard_xid_for_gtid_0_x_1000");
+ goto skip_relay_logging;
+ }
/* Inject an event group that is missing its XID commit event. */
if (mi->last_queued_gtid.domain_id == 0 &&
mi->last_queued_gtid.seq_no == 1000)
@@ -6716,15 +6781,48 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
}
};);
- if (mi->using_gtid != Master_info::USE_GTID_NO && mi->gtid_event_seen)
+ if (mi->using_gtid != Master_info::USE_GTID_NO)
{
- if (unlikely(mi->gtid_reconnect_event_skip_count))
+ if (likely(mi->gtid_event_seen))
{
- --mi->gtid_reconnect_event_skip_count;
- gtid_skip_enqueue= true;
+ if (unlikely(mi->gtid_reconnect_event_skip_count))
+ {
+ if (!got_gtid_event &&
+ mi->gtid_reconnect_event_skip_count ==
+ mi->events_queued_since_last_gtid)
+ goto gtid_not_start; // the 1st re-sent must be gtid
+
+ --mi->gtid_reconnect_event_skip_count;
+ gtid_skip_enqueue= true;
+ }
+ else if (likely(mi->events_queued_since_last_gtid))
+ {
+ DBUG_ASSERT(!got_gtid_event);
+
+ ++mi->events_queued_since_last_gtid;
+ }
+ else if (Log_event::is_group_event((Log_event_type) (uchar)
+ buf[EVENT_TYPE_OFFSET]))
+ {
+ goto gtid_not_start; // no first gtid event in this group
+ }
+ }
+ else if (Log_event::is_group_event((Log_event_type) (uchar)
+ buf[EVENT_TYPE_OFFSET]))
+ {
+ gtid_not_start:
+
+ DBUG_ASSERT(!got_gtid_event);
+
+ error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
+ sql_print_error("The current group of events starts with "
+ "a non-GTID %s event; "
+ "the last seen GTID is %u-%u-%llu",
+ Log_event::get_type_str((Log_event_type) (uchar)
+ buf[EVENT_TYPE_OFFSET]),
+ mi->last_queued_gtid);
+ goto err;
}
- else if (mi->events_queued_since_last_gtid)
- ++mi->events_queued_since_last_gtid;
}
if (!is_compress_event)
@@ -6917,11 +7015,13 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
The whole of the current event group is queued. So in case of
reconnect we can start from after the current GTID.
*/
- if (mi->gtid_reconnect_event_skip_count)
+ if (gtid_skip_enqueue)
{
bool first= true;
StringBuffer<1024> gtid_text;
+ DBUG_ASSERT(mi->events_queued_since_last_gtid > 1);
+
rpl_slave_state_tostring_helper(&gtid_text, &mi->last_queued_gtid,
&first);
sql_print_error("Slave IO thread received a terminal event from "
@@ -6931,12 +7031,39 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
gtid_text.ptr(),
mi->gtid_reconnect_event_skip_count,
mi->events_queued_since_last_gtid);
+ error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
+ goto err;
}
mi->gtid_current_pos.update(&mi->last_queued_gtid);
mi->events_queued_since_last_gtid= 0;
- /* Reset the domain_id_filter flag. */
- mi->domain_id_filter.reset_filter();
+ if (unlikely(gtid_skip_enqueue))
+ {
+ error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
+ sql_print_error("Recieved a group closing %s event "
+ "at %llu position in the group while there are "
+ "still %llu events to skip upon reconnecting; "
+ "the last seen GTID is %u-%u-%llu",
+ Log_event::get_type_str((Log_event_type) (uchar)
+ buf[EVENT_TYPE_OFFSET]),
+ (mi->events_queued_since_last_gtid -
+ mi->gtid_reconnect_event_skip_count),
+ mi->events_queued_since_last_gtid,
+ mi->last_queued_gtid);
+ goto err;
+ }
+ else
+ {
+ /*
+ The whole of the current event group is queued. So in case of
+ reconnect we can start from after the current GTID.
+ */
+ mi->gtid_current_pos.update(&mi->last_queued_gtid);
+ mi->events_queued_since_last_gtid= 0;
+
+ /* Reset the domain_id_filter flag. */
+ mi->domain_id_filter.reset_filter();
+ }
}
skip_relay_logging:
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index e4ffbdcb155..e97f24c5487 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -312,3 +312,12 @@ sp_cache::cleanup()
{
my_hash_free(&m_hashtable);
}
+
+
+void Sp_caches::sp_caches_clear()
+{
+ sp_cache_clear(&sp_proc_cache);
+ sp_cache_clear(&sp_func_cache);
+ sp_cache_clear(&sp_package_spec_cache);
+ sp_cache_clear(&sp_package_body_cache);
+}
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 1d1199aaa62..cc121c05a01 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -791,7 +791,7 @@ void
sp_head::set_stmt_end(THD *thd)
{
Lex_input_stream *lip= & thd->m_parser_state->m_lip; /* shortcut */
- const char *end_ptr= lip->get_cpp_ptr(); /* shortcut */
+ const char *end_ptr= lip->get_cpp_tok_start(); /* shortcut */
/* Make the string of parameters. */
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 6203e5672fe..489f9f3c24d 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -812,11 +812,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
(my_hash_get_key) get_sequence_last_key,
(my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC);
- sp_proc_cache= NULL;
- sp_func_cache= NULL;
- sp_package_spec_cache= NULL;
- sp_package_body_cache= NULL;
-
/* For user vars replication*/
if (opt_bin_log)
my_init_dynamic_array(&user_var_events,
@@ -1383,10 +1378,7 @@ void THD::change_user(void)
my_hash_init(&sequences, system_charset_info, SEQUENCES_HASH_SIZE, 0, 0,
(my_hash_get_key) get_sequence_last_key,
(my_hash_free_key) free_sequence_last, HASH_THREAD_SPECIFIC);
- sp_cache_clear(&sp_proc_cache);
- sp_cache_clear(&sp_func_cache);
- sp_cache_clear(&sp_package_spec_cache);
- sp_cache_clear(&sp_package_body_cache);
+ sp_caches_clear();
}
/**
@@ -1512,10 +1504,7 @@ void THD::cleanup(void)
my_hash_free(&user_vars);
my_hash_free(&sequences);
- sp_cache_clear(&sp_proc_cache);
- sp_cache_clear(&sp_func_cache);
- sp_cache_clear(&sp_package_spec_cache);
- sp_cache_clear(&sp_package_body_cache);
+ sp_caches_clear();
auto_inc_intervals_forced.empty();
auto_inc_intervals_in_cur_stmt_for_binlog.empty();
diff --git a/sql/sql_class.h b/sql/sql_class.h
index b4428714c28..d278a797c07 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2167,6 +2167,39 @@ struct wait_for_commit
void reinit();
};
+
+class Sp_caches
+{
+public:
+ sp_cache *sp_proc_cache;
+ sp_cache *sp_func_cache;
+ sp_cache *sp_package_spec_cache;
+ sp_cache *sp_package_body_cache;
+ Sp_caches()
+ :sp_proc_cache(NULL),
+ sp_func_cache(NULL),
+ sp_package_spec_cache(NULL),
+ sp_package_body_cache(NULL)
+ { }
+ ~Sp_caches()
+ {
+ // All caches must be freed by the caller explicitly
+ DBUG_ASSERT(sp_proc_cache == NULL);
+ DBUG_ASSERT(sp_func_cache == NULL);
+ DBUG_ASSERT(sp_package_spec_cache == NULL);
+ DBUG_ASSERT(sp_package_body_cache == NULL);
+ }
+ void sp_caches_swap(Sp_caches &rhs)
+ {
+ swap_variables(sp_cache*, sp_proc_cache, rhs.sp_proc_cache);
+ swap_variables(sp_cache*, sp_func_cache, rhs.sp_func_cache);
+ swap_variables(sp_cache*, sp_package_spec_cache, rhs.sp_package_spec_cache);
+ swap_variables(sp_cache*, sp_package_body_cache, rhs.sp_package_body_cache);
+ }
+ void sp_caches_clear();
+};
+
+
extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
/**
@@ -2185,7 +2218,8 @@ class THD :public Statement,
*/
public Item_change_list,
public MDL_context_owner,
- public Open_tables_state
+ public Open_tables_state,
+ public Sp_caches
{
private:
inline bool is_stmt_prepare() const
@@ -3180,10 +3214,6 @@ public:
enum_sql_command last_sql_command; // Last sql_command exceuted in mysql_execute_command()
sp_rcontext *spcont; // SP runtime context
- sp_cache *sp_proc_cache;
- sp_cache *sp_func_cache;
- sp_cache *sp_package_spec_cache;
- sp_cache *sp_package_body_cache;
/** number of name_const() substitutions, see sp_head.cc:subst_spvars() */
uint query_name_consts;
diff --git a/sql/sql_expression_cache.cc b/sql/sql_expression_cache.cc
index 351ec258ddb..bc44ecd79fa 100644
--- a/sql/sql_expression_cache.cc
+++ b/sql/sql_expression_cache.cc
@@ -63,7 +63,7 @@ void Expression_cache_tmptable::disable_cache()
cache_table= NULL;
update_tracker();
if (tracker)
- tracker->cache= NULL;
+ tracker->detach_from_cache();
}
@@ -189,6 +189,8 @@ Expression_cache_tmptable::~Expression_cache_tmptable()
else
{
update_tracker();
+ if (tracker)
+ tracker->detach_from_cache();
tracker= NULL;
}
}
diff --git a/sql/sql_expression_cache.h b/sql/sql_expression_cache.h
index 61e0c4c69b3..d4bb252dccb 100644
--- a/sql/sql_expression_cache.h
+++ b/sql/sql_expression_cache.h
@@ -83,7 +83,11 @@ public:
cache(c), hit(0), miss(0), state(UNINITED)
{}
+private:
+ // This can be NULL if the cache is already deleted
Expression_cache *cache;
+
+public:
ulong hit, miss;
enum expr_cache_state state;
@@ -91,6 +95,7 @@ public:
void set(ulong h, ulong m, enum expr_cache_state s)
{hit= h; miss= m; state= s;}
+ void detach_from_cache() { cache= NULL; }
void fetch_current_stats()
{
if (cache)
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 3475b622130..c86458c438d 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -701,8 +701,10 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler,
if (!in_prepare)
{
MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->write_set);
- (void) item->save_in_field(key_part->field, 1);
+ int res= item->save_in_field(key_part->field, 1);
dbug_tmp_restore_column_map(&table->write_set, old_map);
+ if (res)
+ return 1;
}
key_len+= key_part->store_length;
keypart_map= (keypart_map << 1) | 1;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 864afc71311..d437da4b7cd 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -17144,8 +17144,7 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field,
table->s->db_create_options|= HA_OPTION_PACK_RECORD;
else if (org_field->type() == FIELD_TYPE_DOUBLE)
((Field_double *) new_field)->not_fixed= TRUE;
- new_field->vcol_info= new_field->default_value=
- new_field->check_constraint= 0;
+ new_field->vcol_info= 0;
new_field->cond_selectivity= 1.0;
new_field->next_equal_field= NULL;
new_field->option_list= NULL;
@@ -17740,6 +17739,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
table->intersect_keys.init();
table->keys_in_use_for_query.init();
table->no_rows_with_nulls= param->force_not_null_cols;
+ table->expr_arena= thd;
table->s= share;
init_tmp_table_share(thd, share, "", 0, "(temporary)", tmpname);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 6f607c2dfb0..1316dcd9c94 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -5143,6 +5143,7 @@ public:
int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
+ DBUG_ENTER("get_all_tables");
LEX *lex= thd->lex;
TABLE *table= tables->table;
TABLE_LIST table_acl_check;
@@ -5160,7 +5161,29 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
uint table_open_method= tables->table_open_method;
bool can_deadlock;
MEM_ROOT tmp_mem_root;
- DBUG_ENTER("get_all_tables");
+ /*
+ We're going to open FRM files for tables.
+ In case of VIEWs that contain stored function calls,
+ these stored functions will be parsed and put to the SP cache.
+
+ Suppose we have a view containing a stored function call:
+ CREATE VIEW v1 AS SELECT f1() AS c1;
+ and now we're running:
+ SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=f1();
+ If a parallel thread invalidates the cache,
+ e.g. by creating or dropping some stored routine,
+ the SELECT query will re-parse f1() when processing "v1"
+ and replace the outdated cached version of f1() to a new one.
+ But the old version of f1() is referenced from the m_sp member
+ of the Item_func_sp instances used in the WHERE condition.
+ We cannot destroy it. To avoid such clashes, let's remember
+ all old routines into a temporary SP cache collection
+ and process tables with a new empty temporary SP cache collection.
+ Then restore to the old SP cache collection at the end.
+ */
+ Sp_caches old_sp_caches;
+
+ old_sp_caches.sp_caches_swap(*thd);
bzero(&tmp_mem_root, sizeof(tmp_mem_root));
@@ -5334,6 +5357,13 @@ err:
thd->restore_backup_open_tables_state(&open_tables_state_backup);
free_root(&tmp_mem_root, 0);
+ /*
+ Now restore to the saved SP cache collection
+ and clear the temporary SP cache collection.
+ */
+ old_sp_caches.sp_caches_swap(*thd);
+ old_sp_caches.sp_caches_clear();
+
DBUG_RETURN(error);
}
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 128a4e68533..c92a437259f 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -1099,7 +1099,6 @@ Type_handler_decimal_result::make_num_distinct_aggregator_field(
const Item *item)
const
{
- DBUG_ASSERT(item->decimals <= DECIMAL_MAX_SCALE);
return new (mem_root)
Field_new_decimal(NULL, item->max_length,
(uchar *) (item->maybe_null ? "" : 0),
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 9a0a9f3149e..770e5e1c3e7 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -899,7 +899,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
/*
We should not introduce any further shift/reduce conflicts.
*/
-%expect 81
+%expect 85
/*
Comments for TOKENS.
@@ -1012,6 +1012,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token FIRST_VALUE_SYM /* SQL-2011 */
%token FLOAT_NUM
%token FLOAT_SYM /* SQL-2003-R */
+%token FORCE_LOOKAHEAD /* INTERNAL never returned by the lexer */
%token FOREIGN /* SQL-2003-R */
%token FOR_SYM /* SQL-2003-R */
%token FOR_SYSTEM_TIME_SYM /* INTERNAL */
@@ -3060,6 +3061,9 @@ sequence_def:
}
;
+/* this rule is used to force look-ahead in the parser */
+force_lookahead: {} | FORCE_LOOKAHEAD {} ;
+
server_def:
SERVER_SYM opt_if_not_exists ident_or_text
{
@@ -3260,7 +3264,7 @@ ev_sql_stmt:
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
}
- sp_proc_stmt
+ sp_proc_stmt force_lookahead
{
LEX *lex= thd->lex;
@@ -18018,8 +18022,8 @@ trigger_tail:
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
}
- sp_proc_stmt /* $19 */
- { /* $20 */
+ sp_proc_stmt /* $19 */ force_lookahead /* $20 */
+ { /* $21 */
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -18102,7 +18106,7 @@ sf_tail:
lex->sphead->set_chistics(lex->sp_chistics);
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
}
- sp_proc_stmt_in_returns_clause
+ sp_proc_stmt_in_returns_clause force_lookahead
{
if (unlikely(Lex->sp_body_finalize_function(thd)))
MYSQL_YYABORT;
@@ -18123,7 +18127,7 @@ sp_tail:
Lex->sphead->set_chistics(Lex->sp_chistics);
Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
}
- sp_proc_stmt
+ sp_proc_stmt force_lookahead
{
if (unlikely(Lex->sp_body_finalize_procedure(thd)))
MYSQL_YYABORT;
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index ea7ba454d0b..23e4a5deb7d 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -293,7 +293,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
/*
We should not introduce any further shift/reduce conflicts.
*/
-%expect 83
+%expect 87
/*
Comments for TOKENS.
@@ -406,6 +406,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token FIRST_VALUE_SYM /* SQL-2011 */
%token FLOAT_NUM
%token FLOAT_SYM /* SQL-2003-R */
+%token FORCE_LOOKAHEAD /* INTERNAL never returned by the lexer */
%token FOREIGN /* SQL-2003-R */
%token FOR_SYM /* SQL-2003-R */
%token FOR_SYSTEM_TIME_SYM /* INTERNAL */
@@ -2693,6 +2694,9 @@ sequence_def:
}
;
+/* this rule is used to force look-ahead in the parser */
+force_lookahead: {} | FORCE_LOOKAHEAD {} ;
+
server_def:
SERVER_SYM opt_if_not_exists ident_or_text
{
@@ -2893,7 +2897,7 @@ ev_sql_stmt:
lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
}
- sp_proc_stmt
+ sp_proc_stmt force_lookahead
{
LEX *lex= thd->lex;
@@ -18084,8 +18088,8 @@ trigger_tail:
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
}
- sp_proc_stmt /* $19 */
- { /* $20 */
+ sp_proc_stmt /* $19 */ force_lookahead /* $20 */
+ { /* $21 */
LEX *lex= Lex;
sp_head *sp= lex->sphead;
if (unlikely(sp->check_unresolved_goto()))
@@ -18171,7 +18175,7 @@ sf_tail:
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
}
sp_tail_is
- sp_body
+ sp_body force_lookahead
{
if (unlikely(Lex->sp_body_finalize_function(thd)))
MYSQL_YYABORT;
@@ -18198,7 +18202,7 @@ sp_tail:
Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
}
sp_tail_is
- sp_body
+ sp_body force_lookahead
{
if (unlikely(Lex->sp_body_finalize_procedure(thd)))
MYSQL_YYABORT;
diff --git a/sql/table.cc b/sql/table.cc
index eac89d4b4c5..64fb3150a39 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -6196,7 +6196,7 @@ Item *Field_iterator_view::create_item(THD *thd)
Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
LEX_CSTRING *name)
{
- bool save_wrapper= thd->lex->select_lex.no_wrap_view_item;
+ bool save_wrapper= thd->lex->current_select->no_wrap_view_item;
Item *field= *field_ref;
DBUG_ENTER("create_view_field");
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 96b43e3d7f1..dfd0301037f 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -2634,7 +2634,7 @@ static struct my_option my_long_options[] =
&opt_verbose, &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"version", 'V', "Output version information and exit.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"skip-write-binlog", 'S', "Do not replicate changes to time zone tables to other nodes in a Galera cluster.",
+ {"skip-write-binlog", 'S', "Do not replicate changes to time zone tables to the binary log, or to other nodes in a Galera cluster.",
&opt_skip_write_binlog,&opt_skip_write_binlog, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -2730,9 +2730,9 @@ main(int argc, char **argv)
sql_log_bin and wsrep_on to avoid Galera replicating below
truncate table clauses. This will allow user to set different
time zones to nodes in Galera cluster. */
- printf("set @prep1=if((select count(*) from information_schema.global_variables where variable_name='wsrep_on' and variable_value='ON'), 'SET SESSION SQL_LOG_BIN=?, WSREP_ON=OFF;', 'do ?');\n"
- "prepare set_wsrep_write_binlog from @prep1;\n"
- "set @toggle=0; execute set_wsrep_write_binlog using @toggle;\n");
+ printf("set @prep1=if((select count(*) from information_schema.global_variables where variable_name='wsrep_on' and variable_value='ON'), 'SET SESSION WSREP_ON=OFF', 'do 0');\n"
+ "SET SESSION SQL_LOG_BIN=0;\n"
+ "execute immediate @prep1;\n");
}
else
{