diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2022-05-03 10:59:54 +0200 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2022-05-03 10:59:54 +0200 |
commit | 9614fde1aac6ffa4745804342ff70a96b2418e30 (patch) | |
tree | d53f4578ce0a6b5cf30f3eef854d50c16fbabcee /sql | |
parent | 182b8a29e7a1a0f0fbffeed39518c2c9dc026e13 (diff) | |
parent | 70555454b4c224e85383d482411961c7f2eba2e2 (diff) | |
download | mariadb-git-9614fde1aac6ffa4745804342ff70a96b2418e30.tar.gz |
Merge branch '10.2' into 10.3
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 17 | ||||
-rw-r--r-- | sql/field.h | 2 | ||||
-rw-r--r-- | sql/handler.cc | 3 | ||||
-rw-r--r-- | sql/item_func.cc | 2 | ||||
-rw-r--r-- | sql/item_subselect.cc | 26 | ||||
-rw-r--r-- | sql/item_sum.cc | 6 | ||||
-rw-r--r-- | sql/rpl_gtid.h | 1 | ||||
-rw-r--r-- | sql/slave.cc | 165 | ||||
-rw-r--r-- | sql/sp_cache.cc | 9 | ||||
-rw-r--r-- | sql/sp_head.cc | 2 | ||||
-rw-r--r-- | sql/sql_class.cc | 15 | ||||
-rw-r--r-- | sql/sql_class.h | 40 | ||||
-rw-r--r-- | sql/sql_expression_cache.cc | 4 | ||||
-rw-r--r-- | sql/sql_expression_cache.h | 5 | ||||
-rw-r--r-- | sql/sql_handler.cc | 4 | ||||
-rw-r--r-- | sql/sql_select.cc | 4 | ||||
-rw-r--r-- | sql/sql_show.cc | 32 | ||||
-rw-r--r-- | sql/sql_type.cc | 1 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 16 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 16 | ||||
-rw-r--r-- | sql/table.cc | 2 | ||||
-rw-r--r-- | sql/tztime.cc | 8 |
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(>id_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 { |