diff options
Diffstat (limited to 'sql')
40 files changed, 723 insertions, 231 deletions
diff --git a/sql/field.cc b/sql/field.cc index c5d72abc526..8cd619571c4 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2401,7 +2401,7 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) bool Field::get_date(MYSQL_TIME *to, date_mode_t mode) { StringBuffer<40> tmp; - Temporal::Warn_push warn(get_thd(), NULL, NullS, to, mode); + Temporal::Warn_push warn(get_thd(), nullptr, nullptr, nullptr, to, mode); Temporal_hybrid *t= new(to) Temporal_hybrid(get_thd(), &warn, val_str(&tmp), mode); return !t->is_valid_temporal(); @@ -10887,14 +10887,16 @@ void Field::set_datetime_warning(Sql_condition::enum_warning_level level, if (thd->really_abort_on_warning() && level >= Sql_condition::WARN_LEVEL_WARN) { /* - field_str.name can be NULL when field is not in the select list: + field_name.str can be NULL when field is not in the select list: SET SESSION SQL_MODE= 'STRICT_ALL_TABLES,NO_ZERO_DATE'; CREATE OR REPLACE TABLE t2 SELECT 1 AS f FROM t1 GROUP BY FROM_DAYS(d); Can't call push_warning_truncated_value_for_field() directly here, as it expect a non-NULL name. */ thd->push_warning_wrong_or_truncated_value(level, false, typestr, - str->ptr(), table->s, + str->ptr(), + table->s->db.str, + table->s->table_name.str, field_name.str); } else diff --git a/sql/handler.h b/sql/handler.h index 1acf816dcb9..d55a83c9b93 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2514,6 +2514,9 @@ public: /** true for online operation (LOCK=NONE) */ bool online; + /** which ALGORITHM and LOCK are supported by the storage engine */ + enum_alter_inplace_result inplace_supported; + /** Can be set by handler to describe why a given operation cannot be done in-place (HA_ALTER_INPLACE_NOT_SUPPORTED) or why it cannot be done diff --git a/sql/item.cc b/sql/item.cc index 5c662e5e6ff..3ea1a493db2 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1395,8 +1395,10 @@ bool Item::get_date_from_real(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate bool Item::get_date_from_string(THD *thd, MYSQL_TIME *to, date_mode_t mode) { StringBuffer<MAX_DATETIME_FULL_WIDTH+1> tmp; - Temporal::Warn_push warn(thd, field_table_or_null(), field_name_or_null(), - to, mode); + const TABLE_SHARE *s = field_table_or_null(); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, + field_name_or_null(), to, mode); Temporal_hybrid *t= new(to) Temporal_hybrid(thd, &warn, val_str(&tmp), mode); return !t->is_valid_temporal(); } @@ -2562,14 +2564,7 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, bool res= FALSE; uint i; - /* - In case we're in statement prepare, create conversion item - in its memory: it will be reused on each execute. - */ - Query_arena backup; - Query_arena *arena= thd->stmt_arena->is_stmt_prepare() ? - thd->activate_stmt_arena_if_needed(&backup) : - NULL; + DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare()); for (i= 0, arg= args; i < nargs; i++, arg+= item_sep) { @@ -2591,20 +2586,8 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, res= TRUE; break; // we cannot return here, we need to restore "arena". } - /* - If in statement prepare, then we create a converter for two - constant items, do it once and then reuse it. - If we're in execution of a prepared statement, arena is NULL, - and the conv was created in runtime memory. This can be - the case only if the argument is a parameter marker ('?'), - because for all true constants the charset converter has already - been created in prepare. In this case register the change for - rollback. - */ - if (thd->stmt_arena->is_stmt_prepare()) - *arg= conv; - else - thd->change_item_tree(arg, conv); + + thd->change_item_tree(arg, conv); if (conv->fix_fields_if_needed(thd, arg)) { @@ -2612,8 +2595,6 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, break; // we cannot return here, we need to restore "arena". } } - if (arena) - thd->restore_active_arena(arena, &backup); return res; } @@ -4142,7 +4123,7 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type, { ErrConvTime str(&value.time); make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, - &str, time_type, 0, 0); + &str, time_type, NULL, NULL, NULL); set_zero_time(&value.time, time_type); } maybe_null= 0; diff --git a/sql/item_create.cc b/sql/item_create.cc index edf44fc3cd3..62f4d9f9fee 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. - Copyright (c) 2008-2011 Monty Program Ab + Copyright (c) 2008, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/item_func.cc b/sql/item_func.cc index 9e30afd0239..813927df32b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2288,10 +2288,13 @@ bool Item_func_int_val::fix_length_and_dec() { DBUG_ENTER("Item_func_int_val::fix_length_and_dec"); DBUG_PRINT("info", ("name %s", func_name())); - if (args[0]->cast_to_int_type_handler()-> - Item_func_int_val_fix_length_and_dec(this)) + /* + We don't want to translate ENUM/SET to CHAR here. + So let's call real_type_handler(), not type_handler(). + */ + if (args[0]->real_type_handler()->Item_func_int_val_fix_length_and_dec(this)) DBUG_RETURN(TRUE); - DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); + DBUG_PRINT("info", ("Type: %s", real_type_handler()->name().ptr())); DBUG_RETURN(FALSE); } @@ -2299,6 +2302,7 @@ bool Item_func_int_val::fix_length_and_dec() longlong Item_func_ceiling::int_op() { switch (args[0]->result_type()) { + case STRING_RESULT: // hex hybrid case INT_RESULT: return val_int_from_item(args[0]); case DECIMAL_RESULT: @@ -2332,9 +2336,32 @@ my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value) } +bool Item_func_ceiling::date_op(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) +{ + Datetime::Options opt(thd, TIME_FRAC_TRUNCATE); + Datetime *tm= new (to) Datetime(thd, args[0], opt); + tm->ceiling(thd); + null_value= !tm->is_valid_datetime(); + DBUG_ASSERT(maybe_null || !null_value); + return null_value; +} + + +bool Item_func_ceiling::time_op(THD *thd, MYSQL_TIME *to) +{ + static const Time::Options_for_round opt; + Time *tm= new (to) Time(thd, args[0], opt); + tm->ceiling(); + null_value= !tm->is_valid_time(); + DBUG_ASSERT(maybe_null || !null_value); + return null_value; +} + + longlong Item_func_floor::int_op() { switch (args[0]->result_type()) { + case STRING_RESULT: // hex hybrid case INT_RESULT: return val_int_from_item(args[0]); case DECIMAL_RESULT: @@ -2372,6 +2399,28 @@ my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value) } +bool Item_func_floor::date_op(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) +{ + // DATETIME is not negative, so FLOOR means just truncation + Datetime::Options opt(thd, TIME_FRAC_TRUNCATE); + Datetime *tm= new (to) Datetime(thd, args[0], opt, 0); + null_value= !tm->is_valid_datetime(); + DBUG_ASSERT(maybe_null || !null_value); + return null_value; +} + + +bool Item_func_floor::time_op(THD *thd, MYSQL_TIME *to) +{ + static const Time::Options_for_round opt; + Time *tm= new (to) Time(thd, args[0], opt); + tm->floor(); + null_value= !tm->is_valid_time(); + DBUG_ASSERT(maybe_null || !null_value); + return null_value; +} + + void Item_func_round::fix_length_and_dec_decimal(uint decimals_to_set) { int decimals_delta= args[0]->decimals - decimals_to_set; @@ -2467,8 +2516,27 @@ void Item_func_round::fix_arg_datetime() } -void Item_func_round::fix_arg_int() +/** + Calculate data type and attributes for INT-alike input. + + @param [IN] preferred - The preferred data type handler for simple cases + such as ROUND(x) and TRUNCATE(x,0), when the input + is short enough to fit into an integer type + (without extending to DECIMAL). + - If `preferred` is not NULL, then the code tries + to preserve the given data type handler and + the data type attributes `preferred_attrs`. + - If `preferred` is NULL, then the code fully + calculates attributes using + args[0]->decimal_precision() and chooses between + INT and BIGINT, depending on attributes. + @param [IN] preferred_attrs - The preferred data type attributes for + simple cases. +*/ +void Item_func_round::fix_arg_int(const Type_handler *preferred, + const Type_std_attributes *preferred_attrs) { + DBUG_ASSERT(args[0]->decimals == 0); if (args[1]->const_item()) { Longlong_hybrid val1= args[1]->to_longlong_hybrid(); @@ -2477,13 +2545,35 @@ void Item_func_round::fix_arg_int() else if ((!val1.to_uint(DECIMAL_MAX_SCALE) && truncate) || args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS) { + // Here we can keep INT_RESULT // Length can increase in some cases: ROUND(9,-1) -> 10 int length_can_increase= MY_TEST(!truncate && val1.neg()); - max_length= args[0]->max_length + length_can_increase; - // Here we can keep INT_RESULT - unsigned_flag= args[0]->unsigned_flag; - decimals= 0; - set_handler(type_handler_long_or_longlong()); + if (preferred) + { + Type_std_attributes::set(preferred_attrs); + if (!length_can_increase) + { + // Preserve the exact data type and attributes + set_handler(preferred); + } + else + { + max_length++; + set_handler(type_handler_long_or_longlong()); + } + } + else + { + /* + This branch is currently used for hex hybrid only. + It's known to be unsigned. So sign length is 0. + */ + DBUG_ASSERT(args[0]->unsigned_flag); // no needs to add sign length + max_length= args[0]->decimal_precision() + length_can_increase; + unsigned_flag= true; + decimals= 0; + set_handler(type_handler_long_or_longlong()); + } } else fix_length_and_dec_decimal(val1.to_uint(DECIMAL_MAX_SCALE)); @@ -2610,9 +2700,7 @@ bool Item_func_round::time_op(THD *thd, MYSQL_TIME *to) { DBUG_ASSERT(args[0]->type_handler()->mysql_timestamp_type() == MYSQL_TIMESTAMP_TIME); - Time::Options opt(Time::default_flags_for_get_date(), - truncate ? TIME_FRAC_TRUNCATE : TIME_FRAC_ROUND, - Time::DATETIME_TO_TIME_DISALLOW); + Time::Options_for_round opt(truncate ? TIME_FRAC_TRUNCATE : TIME_FRAC_ROUND); Longlong_hybrid_null dec= args[1]->to_longlong_hybrid_null(); Time *tm= new (to) Time(thd, args[0], opt, dec.to_uint(TIME_SECOND_PART_DIGITS)); diff --git a/sql/item_func.h b/sql/item_func.h index 4922d20bd0c..07ee913b07d 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -450,6 +450,25 @@ public: :Item_func(thd, item), Type_handler_hybrid_field_type(item) { } const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } + void fix_length_and_dec_long_or_longlong(uint char_length, bool unsigned_arg) + { + collation= DTCollation_numeric(); + unsigned_flag= unsigned_arg; + max_length= char_length; + set_handler(Type_handler::type_handler_long_or_longlong(char_length, + unsigned_arg)); + } + void fix_length_and_dec_ulong_or_ulonglong_by_nbits(uint nbits) + { + uint digits= Type_handler_bit::Bit_decimal_notation_int_digits_by_nbits(nbits); + collation= DTCollation_numeric(); + unsigned_flag= true; + max_length= digits; + if (nbits > 32) + set_handler(&type_handler_ulonglong); + else + set_handler(&type_handler_ulong); + } }; @@ -1813,13 +1832,32 @@ public: }; -class Item_func_int_val :public Item_func_num1 +class Item_func_int_val :public Item_func_hybrid_field_type { public: - Item_func_int_val(THD *thd, Item *a): Item_func_num1(thd, a) {} + Item_func_int_val(THD *thd, Item *a): Item_func_hybrid_field_type(thd, a) {} + bool check_partition_func_processor(void *int_arg) { return FALSE; } + bool check_vcol_func_processor(void *arg) { return FALSE; } void fix_length_and_dec_double(); void fix_length_and_dec_int_or_decimal(); + void fix_length_and_dec_time() + { + fix_attributes_time(0); + set_handler(&type_handler_time2); + } + void fix_length_and_dec_datetime() + { + fix_attributes_datetime(0); + set_handler(&type_handler_datetime2); + maybe_null= true; // E.g. CEILING(TIMESTAMP'0000-01-01 23:59:59.9') + } bool fix_length_and_dec(); + String *str_op(String *str) { DBUG_ASSERT(0); return 0; } + bool native_op(THD *thd, Native *to) + { + DBUG_ASSERT(0); + return true; + } }; @@ -1831,6 +1869,8 @@ public: longlong int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); + bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); + bool time_op(THD *thd, MYSQL_TIME *ltime); Item *get_copy(THD *thd) { return get_item_copy<Item_func_ceiling>(thd, this); } }; @@ -1844,6 +1884,8 @@ public: longlong int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); + bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); + bool time_op(THD *thd, MYSQL_TIME *ltime); Item *get_copy(THD *thd) { return get_item_copy<Item_func_floor>(thd, this); } }; @@ -1875,14 +1917,19 @@ public: return NULL; } void fix_arg_decimal(); - void fix_arg_int(); + void fix_arg_int(const Type_handler *preferred, + const Type_std_attributes *preferred_attributes); void fix_arg_double(); void fix_arg_time(); void fix_arg_datetime(); void fix_arg_temporal(const Type_handler *h, uint int_part_length); bool fix_length_and_dec() { - return args[0]->type_handler()->Item_func_round_fix_length_and_dec(this); + /* + We don't want to translate ENUM/SET to CHAR here. + So let's real_type_handler(), not type_handler(). + */ + return args[0]->real_type_handler()->Item_func_round_fix_length_and_dec(this); } Item *get_copy(THD *thd) { return get_item_copy<Item_func_round>(thd, this); } diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 53fc7efac06..7bc34ee688c 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -449,7 +449,8 @@ static bool extract_date_time(THD *thd, DATE_TIME_FORMAT *format, { ErrConvString err(val_begin, length, &my_charset_bin); make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN, - &err, cached_timestamp_type, 0, NullS); + &err, cached_timestamp_type, + nullptr, nullptr, nullptr); break; } } while (++val != val_end); @@ -1576,7 +1577,7 @@ static void set_sec_part(ulong sec_part, MYSQL_TIME *ltime, Item *item) { ltime->second_part= sec_part; if (item->decimals < TIME_SECOND_PART_DIGITS) - my_time_trunc(ltime, item->decimals); + my_datetime_trunc(ltime, item->decimals); } } diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index 25e86c5d777..24c2ef5a2f2 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -556,12 +556,10 @@ void Item_window_func::print(String *str, enum_query_type query_type) } window_func()->print(str, query_type); str->append(" over "); -#ifndef DBUG_OFF - if (!window_spec) // one can call dbug_print_item() anytime in gdb + if (!window_spec) str->append(window_name); else -#endif - window_spec->print(str, query_type); + window_spec->print(str, query_type); } void Item_window_func::print_for_percentile_functions(String *str, enum_query_type query_type) { diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index 94ac4be5427..99ef738ac69 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -651,7 +651,7 @@ class Item_sum_ntile : public Item_sum_int, { public: Item_sum_ntile(THD* thd, Item* num_quantiles_expr) : - Item_sum_int(thd, num_quantiles_expr) + Item_sum_int(thd, num_quantiles_expr), n_old_val_(0) { } longlong val_int() @@ -664,11 +664,13 @@ class Item_sum_ntile : public Item_sum_int, longlong num_quantiles= get_num_quantiles(); - if (num_quantiles <= 0) { + if (num_quantiles <= 0 || + (static_cast<ulonglong>(num_quantiles) != n_old_val_ && n_old_val_ > 0)) + { my_error(ER_INVALID_NTILE_ARGUMENT, MYF(0)); return true; } - + n_old_val_= static_cast<ulonglong>(num_quantiles); null_value= false; ulonglong quantile_size = get_row_count() / num_quantiles; ulonglong extra_rows = get_row_count() - quantile_size * num_quantiles; @@ -694,6 +696,7 @@ class Item_sum_ntile : public Item_sum_int, { current_row_count_= 0; partition_row_count_= 0; + n_old_val_= 0; } const char*func_name() const @@ -717,6 +720,7 @@ class Item_sum_ntile : public Item_sum_int, private: longlong get_num_quantiles() { return args[0]->val_int(); } + ulonglong n_old_val_; }; class Item_sum_percentile_disc : public Item_sum_num, diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc index c53a2b53769..bdc42885312 100644 --- a/sql/log_event_client.cc +++ b/sql/log_event_client.cc @@ -2036,8 +2036,7 @@ bool Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) } else if (strcmp("COMMIT", query) == 0) { - if (my_b_write(&cache, (uchar*) "BEGIN", 5) || - my_b_printf(&cache, "\n%s\n", print_event_info->delimiter)) + if (my_b_printf(&cache, "START TRANSACTION\n%s\n", print_event_info->delimiter)) goto err; } } @@ -2396,7 +2395,7 @@ bool Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) my_b_printf(&cache, "\tXid = %s\n", buf)) goto err; } - if (my_b_printf(&cache, is_flashback ? "BEGIN%s\n" : "COMMIT%s\n", + if (my_b_printf(&cache, is_flashback ? "START TRANSACTION%s\n" : "COMMIT%s\n", print_event_info->delimiter)) goto err; @@ -3899,8 +3898,8 @@ Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info) } else if (!(flags2 & FL_STANDALONE)) { - if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n", - print_event_info->delimiter)) + if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : + "START TRANSACTION\n%s\n", print_event_info->delimiter)) goto err; } diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index fb75bee9f21..49e818b3b97 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -8029,7 +8029,6 @@ end: if (is_table_scan || is_index_scan) issue_long_find_row_warning(get_general_type_code(), m_table->alias.c_ptr(), is_index_scan, rgi); - table->default_column_bitmaps(); DBUG_RETURN(error); } @@ -8264,7 +8263,13 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) #endif /* WSREP_PROC_INFO */ thd_proc_info(thd, message); - int error= find_row(rgi); + // Temporary fix to find out why it fails [/Matz] + memcpy(m_table->read_set->bitmap, m_cols.bitmap, (m_table->read_set->n_bits + 7) / 8); + memcpy(m_table->write_set->bitmap, m_cols_ai.bitmap, (m_table->write_set->n_bits + 7) / 8); + + m_table->mark_columns_per_binlog_row_image(); + + int error= find_row(rgi); if (unlikely(error)) { /* @@ -8334,11 +8339,6 @@ Update_rows_log_event::do_exec_row(rpl_group_info *rgi) goto err; } - // Temporary fix to find out why it fails [/Matz] - memcpy(m_table->read_set->bitmap, m_cols.bitmap, (m_table->read_set->n_bits + 7) / 8); - memcpy(m_table->write_set->bitmap, m_cols_ai.bitmap, (m_table->write_set->n_bits + 7) / 8); - - m_table->mark_columns_per_binlog_row_image(); if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP)) m_table->vers_update_fields(); error= m_table->file->ha_update_row(m_table->record[1], m_table->record[0]); diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 3e173a47f02..ebd92a0e45a 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -45,6 +45,7 @@ #include <violite.h> #include <signal.h> #include "probes_mysql.h" +#include <debug_sync.h> #include "proxy_protocol.h" PSI_memory_key key_memory_NET_buff; @@ -494,6 +495,17 @@ net_write_command(NET *net,uchar command, DBUG_ENTER("net_write_command"); DBUG_PRINT("enter",("length: %lu", (ulong) len)); + DBUG_EXECUTE_IF("simulate_error_on_packet_write", + { + if (command == COM_BINLOG_DUMP) + { + net->last_errno = ER_NET_ERROR_ON_WRITE; + DBUG_ASSERT(!debug_sync_set_action( + (THD *)net->thd, + STRING_WITH_LEN("now SIGNAL parked WAIT_FOR continue"))); + DBUG_RETURN(true); + } + };); MYSQL_NET_WRITE_START(length); buff[4]=command; /* For first packet */ diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 10f82242bca..8ad14ca260c 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2006, 2015, Oracle and/or its affiliates. - Copyright (c) 2010, 2018, MariaDB Corporation. + Copyright (c) 2010, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -864,9 +864,6 @@ void partition_info::vers_set_hist_part(THD *thd) if (next->range_value > thd->query_start()) return; } - my_error(WARN_VERS_PART_FULL, MYF(ME_WARNING|ME_ERROR_LOG), - table->s->db.str, table->s->table_name.str, - vers_info->hist_part->partition_name, "INTERVAL"); } } diff --git a/sql/protocol.cc b/sql/protocol.cc index 5c287cff9e9..c6e2339c0d0 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1579,7 +1579,7 @@ bool Protocol_binary::store(MYSQL_TIME *tm, int decimals) DBUG_ASSERT(decimals == AUTO_SEC_PART_DIGITS || (decimals >= 0 && decimals <= TIME_SECOND_PART_DIGITS)); if (decimals != AUTO_SEC_PART_DIGITS) - my_time_trunc(tm, decimals); + my_datetime_trunc(tm, decimals); int4store(pos+7, tm->second_part); if (tm->second_part) length=11; diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 4cee6cb0dfa..1e5e356a5ba 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -189,7 +189,13 @@ bool sysvartrack_validate_value(THD *thd, const char *str, size_t len) char *token, *lasts= NULL; size_t rest= var_list.length; - if (!var_list.str || var_list.length == 0 || + if (!var_list.str) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), + "session_track_system_variables", "NULL"); + return false; + } + if (var_list.length == 0 || !strcmp(var_list.str, "*")) { return false; diff --git a/sql/slave.cc b/sql/slave.cc index bd3bab224d3..cf94f1dc0b5 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3728,7 +3728,8 @@ static int request_dump(THD *thd, MYSQL* mysql, Master_info* mi, in the future, we should do a better error analysis, but for now we just fill up the error log :-) */ - if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED) + if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED || + mysql_errno(mysql) == ER_NET_ERROR_ON_WRITE) *suppress_warnings= TRUE; // Suppress reconnect warning else sql_print_error("Error on COM_BINLOG_DUMP: %d %s, will retry in %d secs", diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d94016b7815..9cc35d0707f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -800,6 +800,15 @@ class Grant_table_base bool init_read_record(READ_RECORD* info) const { DBUG_ASSERT(m_table); + + if (num_fields() < min_columns) + { + my_printf_error(ER_UNKNOWN_ERROR, "Fatal error: mysql.%s table is " + "damaged or in unsupported 3.20 format", + MYF(ME_ERROR_LOG), m_table->s->table_name.str); + return 1; + } + bool result= ::init_read_record(info, m_table->in_use, m_table, NULL, NULL, 1, true, false); if (!result) @@ -824,7 +833,7 @@ class Grant_table_base protected: friend class Grant_tables; - Grant_table_base() : start_priv_columns(0), end_priv_columns(0), m_table(0) + Grant_table_base() : min_columns(3), start_priv_columns(0), end_priv_columns(0), m_table(0) { } /* Compute how many privilege columns this table has. This method @@ -853,6 +862,9 @@ class Grant_table_base } } + + /* the min number of columns a table should have */ + uint min_columns; /* The index at which privilege columns start. */ uint start_priv_columns; /* The index after the last privilege column */ @@ -1266,7 +1278,7 @@ class User_table_tabular: public User_table friend class Grant_tables; /* Only Grant_tables can instantiate this class. */ - User_table_tabular() {} + User_table_tabular() { min_columns= 13; /* As in 3.20.13 */ } /* The user table is a bit different compared to the other Grant tables. Usually, we only add columns to the grant tables when adding functionality. @@ -1288,13 +1300,6 @@ class User_table_tabular: public User_table int setup_sysvars() const { - if (num_fields() < 13) // number of columns in 3.21 - { - sql_print_error("Fatal error: mysql.user table is damaged or in " - "unsupported 3.20 format."); - return 1; - } - username_char_length= MY_MIN(m_table->field[1]->char_length(), USERNAME_CHAR_LENGTH); using_global_priv_table= false; @@ -1806,7 +1811,7 @@ class Db_table: public Grant_table_base private: friend class Grant_tables; - Db_table() {} + Db_table() { min_columns= 9; /* as in 3.20.13 */ } }; class Tables_priv_table: public Grant_table_base @@ -1824,7 +1829,7 @@ class Tables_priv_table: public Grant_table_base private: friend class Grant_tables; - Tables_priv_table() {} + Tables_priv_table() { min_columns= 8; /* as in 3.22.26a */ } }; class Columns_priv_table: public Grant_table_base @@ -1841,7 +1846,7 @@ class Columns_priv_table: public Grant_table_base private: friend class Grant_tables; - Columns_priv_table() {} + Columns_priv_table() { min_columns= 7; /* as in 3.22.26a */ } }; class Host_table: public Grant_table_base @@ -1853,7 +1858,7 @@ class Host_table: public Grant_table_base private: friend class Grant_tables; - Host_table() {} + Host_table() { min_columns= 8; /* as in 3.20.13 */ } }; class Procs_priv_table: public Grant_table_base @@ -1871,7 +1876,7 @@ class Procs_priv_table: public Grant_table_base private: friend class Grant_tables; - Procs_priv_table() {} + Procs_priv_table() { min_columns=8; } }; class Proxies_priv_table: public Grant_table_base @@ -1888,7 +1893,7 @@ class Proxies_priv_table: public Grant_table_base private: friend class Grant_tables; - Proxies_priv_table() {} + Proxies_priv_table() { min_columns= 7; } }; class Roles_mapping_table: public Grant_table_base @@ -1902,7 +1907,7 @@ class Roles_mapping_table: public Grant_table_base private: friend class Grant_tables; - Roles_mapping_table() {} + Roles_mapping_table() { min_columns= 4; } }; /** diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index a1d235086db..ede30263e48 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - Copyright (c) 2016, 2018, MariaDB Corporation + Copyright (c) 2016, 2020, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -129,10 +129,10 @@ const char* Alter_info::lock() const } -bool Alter_info::supports_algorithm(THD *thd, enum_alter_inplace_result result, +bool Alter_info::supports_algorithm(THD *thd, const Alter_inplace_info *ha_alter_info) { - switch (result) { + switch (ha_alter_info->inplace_supported) { case HA_ALTER_INPLACE_EXCLUSIVE_LOCK: case HA_ALTER_INPLACE_SHARED_LOCK: case HA_ALTER_INPLACE_NO_LOCK: @@ -173,10 +173,10 @@ bool Alter_info::supports_algorithm(THD *thd, enum_alter_inplace_result result, } -bool Alter_info::supports_lock(THD *thd, enum_alter_inplace_result result, +bool Alter_info::supports_lock(THD *thd, const Alter_inplace_info *ha_alter_info) { - switch (result) { + switch (ha_alter_info->inplace_supported) { case HA_ALTER_INPLACE_EXCLUSIVE_LOCK: // If SHARED lock and no particular algorithm was requested, use COPY. if (requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED && @@ -377,7 +377,9 @@ void Alter_table_ctx::report_implicit_default_value_error(THD *thd, thd->push_warning_truncated_value_for_field(Sql_condition::WARN_LEVEL_WARN, h->name().ptr(), h->default_value().ptr(), - s, error_field->field_name.str); + s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, + error_field->field_name.str); } diff --git a/sql/sql_alter.h b/sql/sql_alter.h index ca343f36569..89eb4ebb3e9 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -1,5 +1,5 @@ /* Copyright (c) 2010, 2014, Oracle and/or its affiliates. - Copyright (c) 2013, 2018, MariaDB Corporation. + Copyright (c) 2013, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -203,29 +203,26 @@ public: with the specified user alter algorithm. @param thd Thread handle - @param result Operation supported for inplace alter @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data during in-place alter @retval false Supported operation @retval true Not supported value */ - bool supports_algorithm(THD *thd, enum_alter_inplace_result result, + bool supports_algorithm(THD *thd, const Alter_inplace_info *ha_alter_info); /** Check whether the given result can be supported with the specified user lock type. - @param result Operation supported for inplace alter @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data during in-place alter @retval false Supported lock type @retval true Not supported value */ - bool supports_lock(THD *thd, enum_alter_inplace_result result, - const Alter_inplace_info *ha_alter_info); + bool supports_lock(THD *thd, const Alter_inplace_info *ha_alter_info); /** Return user requested algorithm. If user does not specify diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c85c2b6449a..45ce4be3eb5 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5332,6 +5332,24 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table_list) DBUG_VOID_RETURN; } +int TABLE::fix_vcol_exprs(THD *thd) +{ + for (Field **vf= vfield; vf && *vf; vf++) + if (fix_session_vcol_expr(thd, (*vf)->vcol_info)) + return 1; + + for (Field **df= default_field; df && *df; df++) + if ((*df)->default_value && + fix_session_vcol_expr(thd, (*df)->default_value)) + return 1; + + for (Virtual_column_info **cc= check_constraints; cc && *cc; cc++) + if (fix_session_vcol_expr(thd, (*cc))) + return 1; + + return 0; +} + static bool fix_all_session_vcol_exprs(THD *thd, TABLE_LIST *tables) { @@ -5339,36 +5357,27 @@ static bool fix_all_session_vcol_exprs(THD *thd, TABLE_LIST *tables) TABLE_LIST *first_not_own= thd->lex->first_not_own_table(); DBUG_ENTER("fix_session_vcol_expr"); - for (TABLE_LIST *table= tables; table && table != first_not_own; + int error= 0; + for (TABLE_LIST *table= tables; table && table != first_not_own && !error; table= table->next_global) { TABLE *t= table->table; if (!table->placeholder() && t->s->vcols_need_refixing && table->lock_type >= TL_WRITE_ALLOW_WRITE) { + Query_arena *stmt_backup= thd->stmt_arena; + if (thd->stmt_arena->is_conventional()) + thd->stmt_arena= t->expr_arena; if (table->security_ctx) thd->security_ctx= table->security_ctx; - for (Field **vf= t->vfield; vf && *vf; vf++) - if (fix_session_vcol_expr(thd, (*vf)->vcol_info)) - goto err; - - for (Field **df= t->default_field; df && *df; df++) - if ((*df)->default_value && - fix_session_vcol_expr(thd, (*df)->default_value)) - goto err; - - for (Virtual_column_info **cc= t->check_constraints; cc && *cc; cc++) - if (fix_session_vcol_expr(thd, (*cc))) - goto err; + error= t->fix_vcol_exprs(thd); thd->security_ctx= save_security_ctx; + thd->stmt_arena= stmt_backup; } } - DBUG_RETURN(0); -err: - thd->security_ctx= save_security_ctx; - DBUG_RETURN(1); + DBUG_RETURN(error); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a900e485cd7..af0035e9003 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3754,7 +3754,6 @@ void select_dumpvar::cleanup() Query_arena::Type Query_arena::type() const { - DBUG_ASSERT(0); /* Should never be called */ return STATEMENT; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 08e5af289f3..ab188c18735 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1100,7 +1100,7 @@ public: /* We build without RTTI, so dynamic_cast can't be used. */ enum Type { - STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE + STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE, TABLE_ARENA }; Query_arena(MEM_ROOT *mem_root_arg, enum enum_state state_arg) : @@ -4086,13 +4086,20 @@ public: return 0; } + + bool is_item_tree_change_register_required() + { + return !stmt_arena->is_conventional() + || stmt_arena->type() == Query_arena::TABLE_ARENA; + } + void change_item_tree(Item **place, Item *new_value) { DBUG_ENTER("THD::change_item_tree"); DBUG_PRINT("enter", ("Register: %p (%p) <- %p", *place, place, new_value)); /* TODO: check for OOM condition here */ - if (!stmt_arena->is_conventional()) + if (is_item_tree_change_register_required()) nocheck_register_item_tree_change(place, *place, mem_root); *place= new_value; DBUG_VOID_RETURN; @@ -4588,14 +4595,13 @@ public: void push_warning_truncated_value_for_field(Sql_condition::enum_warning_level level, const char *type_str, const char *val, - const TABLE_SHARE *s, + const char *db_name, + const char *table_name, const char *name) { DBUG_ASSERT(name); char buff[MYSQL_ERRMSG_SIZE]; CHARSET_INFO *cs= &my_charset_latin1; - const char *db_name= s ? s->db.str : NULL; - const char *table_name= s ? s->table_name.str : NULL; if (!db_name) db_name= ""; @@ -4612,12 +4618,13 @@ public: bool totally_useless_value, const char *type_str, const char *val, - const TABLE_SHARE *s, + const char *db_name, + const char *table_name, const char *field_name) { if (field_name) push_warning_truncated_value_for_field(level, type_str, val, - s, field_name); + db_name, table_name, field_name); else if (totally_useless_value) push_warning_wrong_value(level, type_str, val); else diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 913379a4054..baec470c471 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -6787,6 +6787,7 @@ bool LEX::sp_for_loop_cursor_declarations(THD *thd, LEX_CSTRING name; uint coffs, param_count= 0; const sp_pcursor *pcursor; + DBUG_ENTER("LEX::sp_for_loop_cursor_declarations"); if ((item_splocal= item->get_item_splocal())) name= item_splocal->m_name; @@ -6818,23 +6819,23 @@ bool LEX::sp_for_loop_cursor_declarations(THD *thd, else { thd->parse_error(); - return true; + DBUG_RETURN(true); } if (unlikely(!(pcursor= spcont->find_cursor_with_error(&name, &coffs, false)) || pcursor->check_param_count_with_error(param_count))) - return true; + DBUG_RETURN(true); if (!(loop->m_index= sp_add_for_loop_cursor_variable(thd, index, pcursor, coffs, bounds.m_index, item_func_sp))) - return true; + DBUG_RETURN(true); loop->m_target_bound= NULL; loop->m_direction= bounds.m_direction; loop->m_cursor_offset= coffs; loop->m_implicit_cursor= bounds.m_implicit_cursor; - return false; + DBUG_RETURN(false); } @@ -8188,6 +8189,7 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name, const Sp_rcontext_handler *rh; sp_variable *spv; + uint unused_off; DBUG_ASSERT(spcont); DBUG_ASSERT(sphead); if ((spv= find_variable(name, &rh))) @@ -8226,7 +8228,9 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name, return new (thd->mem_root) Item_func_sqlerrm(thd); } - if (!current_select) + if (!select_stack_head() && + (current_select->parsing_place != FOR_LOOP_BOUND || + spcont->find_cursor(name, &unused_off, false) == NULL)) { // we are out of SELECT or FOR so it is syntax error my_error(ER_SP_UNDECLARED_VAR, MYF(0), name->str); @@ -9722,7 +9726,8 @@ Item *LEX::create_item_query_expression(THD *thd, // Add the subtree of subquery to the current SELECT_LEX SELECT_LEX *curr_sel= select_stack_head(); - DBUG_ASSERT(current_select == curr_sel); + DBUG_ASSERT(current_select == curr_sel || + (curr_sel == NULL && current_select == &builtin_select)); if (!curr_sel) { curr_sel= &builtin_select; @@ -9965,7 +9970,8 @@ SELECT_LEX *LEX::parsed_subselect(SELECT_LEX_UNIT *unit) // Add the subtree of subquery to the current SELECT_LEX SELECT_LEX *curr_sel= select_stack_head(); - DBUG_ASSERT(current_select == curr_sel); + DBUG_ASSERT(current_select == curr_sel || + (curr_sel == NULL && current_select == &builtin_select)); if (curr_sel) { curr_sel->register_unit(unit, &curr_sel->context); @@ -10041,7 +10047,8 @@ TABLE_LIST *LEX::parsed_derived_table(SELECT_LEX_UNIT *unit, // Add the subtree of subquery to the current SELECT_LEX SELECT_LEX *curr_sel= select_stack_head(); - DBUG_ASSERT(current_select == curr_sel); + DBUG_ASSERT(current_select == curr_sel || + (curr_sel == NULL && current_select == &builtin_select)); Table_ident *ti= new (thd->mem_root) Table_ident(unit); if (ti == NULL) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index c2cabe4cb36..92d4ec42c8f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3698,8 +3698,9 @@ public: if (unlikely(!select_stack_top)) { - current_select= NULL; - DBUG_PRINT("info", ("Top Select is empty")); + current_select= &builtin_select; + DBUG_PRINT("info", ("Top Select is empty -> sel builtin: %p", + current_select)); } else current_select= select_stack[select_stack_top - 1]; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d3c7b27cbd3..6862610537a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1276,6 +1276,7 @@ bool do_command(THD *thd) command= fetch_command(thd, packet); #ifdef WITH_WSREP + DEBUG_SYNC(thd, "wsrep_before_before_command"); /* Aborted by background rollbacker thread. Handle error here and jump straight to out @@ -8013,8 +8014,8 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, sp_cache_enforce_limit(thd->sp_package_spec_cache, stored_program_cache_size); sp_cache_enforce_limit(thd->sp_package_body_cache, stored_program_cache_size); thd->end_statement(); + thd->Item_change_list::rollback_item_tree_changes(); thd->cleanup_after_query(); - DBUG_ASSERT(thd->Item_change_list::is_empty()); } else { @@ -9116,7 +9117,6 @@ my_bool find_thread_callback(THD *thd, find_thread_callback_arg *arg) if (thd->get_command() != COM_DAEMON && arg->id == (arg->query_id ? thd->query_id : (longlong) thd->thread_id)) { - if (WSREP(thd)) mysql_mutex_lock(&thd->LOCK_thd_data); mysql_mutex_lock(&thd->LOCK_thd_kill); // Lock from delete arg->thd= thd; return 1; @@ -9132,6 +9132,26 @@ THD *find_thread_by_id(longlong id, bool query_id) return arg.thd; } +#ifdef WITH_WSREP +my_bool find_thread_with_thd_data_lock_callback(THD *thd, find_thread_callback_arg *arg) +{ + if (thd->get_command() != COM_DAEMON && + arg->id == (arg->query_id ? thd->query_id : (longlong) thd->thread_id)) + { + if (WSREP(thd)) mysql_mutex_lock(&thd->LOCK_thd_data); + mysql_mutex_lock(&thd->LOCK_thd_kill); // Lock from delete + arg->thd= thd; + return 1; + } + return 0; +} +THD *find_thread_by_id_with_thd_data_lock(longlong id, bool query_id) +{ + find_thread_callback_arg arg(id, query_id); + server_threads.iterate(find_thread_with_thd_data_lock_callback, &arg); + return arg.thd; +} +#endif /** kill one thread. @@ -9149,7 +9169,11 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ uint error= (type == KILL_TYPE_QUERY ? ER_NO_SUCH_QUERY : ER_NO_SUCH_THREAD); DBUG_ENTER("kill_one_thread"); DBUG_PRINT("enter", ("id: %lld signal: %u", id, (uint) kill_signal)); +#ifdef WITH_WSREP + if (id && (tmp= find_thread_by_id_with_thd_data_lock(id, type == KILL_TYPE_QUERY))) +#else if (id && (tmp= find_thread_by_id(id, type == KILL_TYPE_QUERY))) +#endif { /* If we're SUPER, we can KILL anything, including system-threads. @@ -9203,8 +9227,9 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ else error= (type == KILL_TYPE_QUERY ? ER_KILL_QUERY_DENIED_ERROR : ER_KILL_DENIED_ERROR); - +#ifdef WITH_WSREP if (WSREP(tmp)) mysql_mutex_unlock(&tmp->LOCK_thd_data); +#endif mysql_mutex_unlock(&tmp->LOCK_thd_kill); } DBUG_PRINT("exit", ("%d", error)); diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 4526cac5af1..633d969b3de 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2005, 2018, Oracle and/or its affiliates. - Copyright (c) 2010, 2020, MariaDB Corporation + Copyright (c) 2010, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1831,6 +1831,8 @@ static void plugin_load(MEM_ROOT *tmp_root) int error; THD *new_thd= new THD(0); bool result; + unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] = + { MYSQL_AUDIT_GENERAL_CLASSMASK }; DBUG_ENTER("plugin_load"); if (global_system_variables.log_warnings >= 9) @@ -1882,6 +1884,31 @@ static void plugin_load(MEM_ROOT *tmp_root) continue; /* + Pre-acquire audit plugins for events that may potentially occur + during [UN]INSTALL PLUGIN. + + When audit event is triggered, audit subsystem acquires interested + plugins by walking through plugin list. Evidently plugin list + iterator protects plugin list by acquiring LOCK_plugin, see + plugin_foreach_with_mask(). + + On the other hand plugin_load is acquiring LOCK_plugin + rather for a long time. + + When audit event is triggered during plugin_load plugin + list iterator acquires the same lock (within the same thread) + second time. + + This hack should be removed when LOCK_plugin is fixed so it + protects only what it supposed to protect. + + See also mysql_install_plugin(), mysql_uninstall_plugin() and + initialize_audit_plugin() + */ + if (mysql_audit_general_enabled()) + mysql_audit_acquire_plugins(new_thd, event_class_mask); + + /* there're no other threads running yet, so we don't need a mutex. but plugin_add() before is designed to work in multi-threaded environment, and it uses mysql_mutex_assert_owner(), so we lock @@ -2281,27 +2308,30 @@ static bool do_uninstall(THD *thd, TABLE *table, const LEX_CSTRING *name) if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)) || plugin->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_DYING)) { - myf MyFlags= thd->lex->if_exists() ? ME_NOTE : 0; - my_error(ER_SP_DOES_NOT_EXIST, MyFlags, "PLUGIN", name->str); - return !MyFlags; - } - if (!plugin->plugin_dl) - { - my_error(ER_PLUGIN_DELETE_BUILTIN, MYF(0)); - return 1; + // maybe plugin is present in mysql.plugin; postpone the error + plugin= nullptr; } - if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT) + + if (plugin) { - my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str); - return 1; - } + if (!plugin->plugin_dl) + { + my_error(ER_PLUGIN_DELETE_BUILTIN, MYF(0)); + return 1; + } + if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT) + { + my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str); + return 1; + } - plugin->state= PLUGIN_IS_DELETED; - if (plugin->ref_count) - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, - WARN_PLUGIN_BUSY, ER_THD(thd, WARN_PLUGIN_BUSY)); - else - reap_needed= true; + plugin->state= PLUGIN_IS_DELETED; + if (plugin->ref_count) + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, + WARN_PLUGIN_BUSY, ER_THD(thd, WARN_PLUGIN_BUSY)); + else + reap_needed= true; + } uchar user_key[MAX_KEY_LENGTH]; table->use_all_columns(); @@ -2325,6 +2355,12 @@ static bool do_uninstall(THD *thd, TABLE *table, const LEX_CSTRING *name) return 1; } } + else if (!plugin) + { + const myf MyFlags= thd->lex->if_exists() ? ME_NOTE : 0; + my_error(ER_SP_DOES_NOT_EXIST, MyFlags, "PLUGIN", name->str); + return !MyFlags; + } return 0; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 913497b097a..bf531fe4d7d 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -5353,7 +5353,7 @@ bool Protocol_local::store_str(const char *str, size_t length, bool Protocol_local::store(MYSQL_TIME *time, int decimals) { if (decimals != AUTO_SEC_PART_DIGITS) - my_time_trunc(time, decimals); + my_datetime_trunc(time, decimals); return store_column(time, sizeof(MYSQL_TIME)); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 87257bc9ab4..8834c4d26e9 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7804,7 +7804,6 @@ static bool is_inplace_alter_impossible(TABLE *table, @param ha_alter_info Structure describing ALTER TABLE to be carried out and serving as a storage place for data used during different phases. - @param inplace_supported Enum describing the locking requirements. @param target_mdl_request Metadata request/lock on the target table name. @param alter_ctx ALTER TABLE runtime context. @@ -7829,7 +7828,6 @@ static bool mysql_inplace_alter_table(THD *thd, TABLE *table, TABLE *altered_table, Alter_inplace_info *ha_alter_info, - enum_alter_inplace_result inplace_supported, MDL_request *target_mdl_request, Alter_table_ctx *alter_ctx) { @@ -7839,6 +7837,10 @@ static bool mysql_inplace_alter_table(THD *thd, bool reopen_tables= false; bool res; handlerton *hton; + + const enum_alter_inplace_result inplace_supported= + ha_alter_info->inplace_supported; + DBUG_ENTER("mysql_inplace_alter_table"); /* Downgrade DDL lock while we are waiting for exclusive lock below */ @@ -10521,27 +10523,31 @@ do_continue:; if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE) ha_alter_info.online= true; // Ask storage engine whether to use copy or in-place - enum_alter_inplace_result inplace_supported= + ha_alter_info.inplace_supported= table->file->check_if_supported_inplace_alter(&altered_table, &ha_alter_info); - - Key *k; - for (List_iterator<Key> it(alter_info->key_list); - (k= it++) && inplace_supported != HA_ALTER_INPLACE_NOT_SUPPORTED;) + if (ha_alter_info.inplace_supported != HA_ALTER_INPLACE_NOT_SUPPORTED) { - if(k->without_overlaps) - inplace_supported= HA_ALTER_INPLACE_NOT_SUPPORTED; + List_iterator<Key> it(alter_info->key_list); + while (Key *k= it++) + { + if (k->without_overlaps) + { + ha_alter_info.inplace_supported= HA_ALTER_INPLACE_NOT_SUPPORTED; + break; + } + } } - if (alter_info->supports_algorithm(thd, inplace_supported, &ha_alter_info) || - alter_info->supports_lock(thd, inplace_supported, &ha_alter_info)) + if (alter_info->supports_algorithm(thd, &ha_alter_info) || + alter_info->supports_lock(thd, &ha_alter_info)) { cleanup_table_after_inplace_alter(&altered_table); goto err_new_table_cleanup; } // If SHARED lock and no particular algorithm was requested, use COPY. - if (inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK && + if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK && alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED && alter_info->algorithm(thd) == Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT && @@ -10549,7 +10555,7 @@ do_continue:; Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT) use_inplace= false; - if (inplace_supported == HA_ALTER_INPLACE_NOT_SUPPORTED) + if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_NOT_SUPPORTED) use_inplace= false; if (use_inplace) @@ -10562,7 +10568,7 @@ do_continue:; */ thd->count_cuted_fields = CHECK_FIELD_WARN; int res= mysql_inplace_alter_table(thd, table_list, table, &altered_table, - &ha_alter_info, inplace_supported, + &ha_alter_info, &target_mdl_request, &alter_ctx); thd->count_cuted_fields= save_count_cuted_fields; my_free(const_cast<uchar*>(frm.str)); diff --git a/sql/sql_time.cc b/sql/sql_time.cc index c08e54bed87..8bb96dfa776 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -18,7 +18,6 @@ /* Functions to handle date and time */ #include "mariadb.h" -#include "sql_priv.h" #include "sql_time.h" #include "tztime.h" // struct Time_zone #include "sql_class.h" // THD @@ -297,7 +296,7 @@ check_date_with_warn(THD *thd, const MYSQL_TIME *ltime, { ErrConvTime str(ltime); make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN, - &str, ts_type, 0, 0); + &str, ts_type, nullptr, nullptr, nullptr); return true; } return false; @@ -431,7 +430,7 @@ str_to_datetime_with_warn(THD *thd, CHARSET_INFO *cs, const char *str, size_t length, MYSQL_TIME *to, date_mode_t mode) { - Temporal::Warn_push warn(thd, NULL, NullS, to, mode); + Temporal::Warn_push warn(thd, nullptr, nullptr, nullptr, to, mode); Temporal_hybrid *t= new(to) Temporal_hybrid(thd, &warn, str, length, cs, mode); return !t->is_valid_temporal(); } @@ -441,7 +440,9 @@ bool double_to_datetime_with_warn(THD *thd, double value, MYSQL_TIME *ltime, date_mode_t fuzzydate, const TABLE_SHARE *s, const char *field_name) { - Temporal::Warn_push warn(thd, s, field_name, ltime, fuzzydate); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, + field_name, ltime, fuzzydate); Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, value, fuzzydate); return !t->is_valid_temporal(); } @@ -452,7 +453,9 @@ bool decimal_to_datetime_with_warn(THD *thd, const my_decimal *value, date_mode_t fuzzydate, const TABLE_SHARE *s, const char *field_name) { - Temporal::Warn_push warn(thd, s, field_name, ltime, fuzzydate); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, + field_name, ltime, fuzzydate); Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, value, fuzzydate); return !t->is_valid_temporal(); } @@ -467,7 +470,9 @@ bool int_to_datetime_with_warn(THD *thd, const Longlong_hybrid &nr, Note: conversion from an integer to TIME can overflow to '838:59:59.999999', so the conversion result can have fractional digits. */ - Temporal::Warn_push warn(thd, s, field_name, ltime, fuzzydate); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, + field_name, ltime, fuzzydate); Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, &warn, nr, fuzzydate); return !t->is_valid_temporal(); } @@ -896,12 +901,13 @@ void make_truncated_value_warning(THD *thd, Sql_condition::enum_warning_level level, const ErrConv *sval, timestamp_type time_type, - const TABLE_SHARE *s, const char *field_name) + const char *db_name, const char *table_name, + const char *field_name) { const char *type_str= Temporal::type_name_by_timestamp_type(time_type); return thd->push_warning_wrong_or_truncated_value (level, time_type <= MYSQL_TIMESTAMP_ERROR, type_str, sval->ptr(), - s, field_name); + db_name, table_name, field_name); } diff --git a/sql/sql_time.h b/sql/sql_time.h index fe9697adf67..c918eb6d807 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -1,5 +1,5 @@ /* Copyright (c) 2006, 2010, Oracle and/or its affiliates. - Copyright (c) 2011, 2016, MariaDB + Copyright (c) 2011, 2020, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -78,7 +78,7 @@ void make_truncated_value_warning(THD *thd, Sql_condition::enum_warning_level level, const ErrConv *str_val, timestamp_type time_type, - const TABLE_SHARE *s, + const char *db_name, const char *table_name, const char *field_name); extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type, diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 7345b1fb529..bce65e494d3 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -507,17 +507,21 @@ bool Sec6::convert_to_mysql_time(THD *thd, int *warn, MYSQL_TIME *ltime, void Temporal::push_conversion_warnings(THD *thd, bool totally_useless_value, int warn, const char *typestr, - const TABLE_SHARE *s, + const char *db_name, + const char *table_name, const char *field_name, const char *value) { if (MYSQL_TIME_WARN_HAVE_WARNINGS(warn)) thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN, totally_useless_value, - typestr, value, s, field_name); + typestr, value, + db_name, table_name, + field_name); else if (MYSQL_TIME_WARN_HAVE_NOTES(warn)) thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_NOTE, - false, typestr, value, s, + false, typestr, value, + db_name, table_name, field_name); } @@ -1092,7 +1096,7 @@ bool Temporal::datetime_round_or_invalidate(THD *thd, uint dec, int *warn, ulong DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); if (datetime_add_nanoseconds_or_invalidate(thd, warn, nsec)) return true; - my_time_trunc(this, dec); + my_datetime_trunc(this, dec); return false; } @@ -4069,7 +4073,7 @@ uint32 Type_handler_bit::Item_decimal_notation_int_digits(const Item *item) const { - return Bit_decimal_notation_int_digits(item); + return Bit_decimal_notation_int_digits_by_nbits(item->max_length); } @@ -4087,9 +4091,23 @@ Type_handler_general_purpose_int::Item_decimal_notation_int_digits( a divisor. */ uint32 -Type_handler_bit::Bit_decimal_notation_int_digits(const Item *item) -{ - return item->max_length/3+1; +Type_handler_bit::Bit_decimal_notation_int_digits_by_nbits(uint nbits) +{ + DBUG_ASSERT(nbits > 0); + DBUG_ASSERT(nbits <= 64); + set_if_smaller(nbits, 64); // Safety + static uint ndigits[65]= + {0, + 1,1,1,2,2,2,3,3, // 1..8 bits + 3,4,4,4,4,5,5,5, // 9..16 bits + 6,6,6,7,7,7,7,8, // 17..24 bits + 8,8,9,9,9,10,10,10, // 25..32 bits + 10,11,11,11,12,12,12,13, // 33..40 bits + 13,13,13,14,14,14,15,15, // 41..48 bits + 15,16,16,16,16,17,17,17, // 49..56 bits + 18,18,18,19,19,19,19,20 // 57..64 bits + }; + return ndigits[nbits]; } /*************************************************************************/ @@ -4933,7 +4951,9 @@ bool Type_handler::Item_get_date_with_warn(THD *thd, Item *item, MYSQL_TIME *ltime, date_mode_t fuzzydate) const { - Temporal::Warn_push warn(thd, item->field_table_or_null(), + const TABLE_SHARE *s= item->field_table_or_null(); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, item->field_name_or_null(), ltime, fuzzydate); Item_get_date(thd, item, &warn, ltime, fuzzydate); return ltime->time_type < 0; @@ -4945,7 +4965,9 @@ bool Type_handler::Item_func_hybrid_field_type_get_date_with_warn(THD *thd, MYSQL_TIME *ltime, date_mode_t mode) const { - Temporal::Warn_push warn(thd, item->field_table_or_null(), + const TABLE_SHARE *s= item->field_table_or_null(); + Temporal::Warn_push warn(thd, s ? s->db.str : nullptr, + s ? s->table_name.str : nullptr, item->field_name_or_null(), ltime, mode); Item_func_hybrid_field_type_get_date(thd, item, &warn, ltime, mode); return ltime->time_type < 0; @@ -6143,7 +6165,40 @@ bool Type_handler_row:: bool Type_handler_int_result:: Item_func_round_fix_length_and_dec(Item_func_round *item) const { - item->fix_arg_int(); + item->fix_arg_int(this, item->arguments()[0]); + return false; +} + + +bool Type_handler_year:: + Item_func_round_fix_length_and_dec(Item_func_round *item) const +{ + item->fix_arg_int(&type_handler_ulong, item->arguments()[0]); + return false; +} + + +bool Type_handler_hex_hybrid:: + Item_func_round_fix_length_and_dec(Item_func_round *item) const +{ + item->fix_arg_int(nullptr, nullptr); + return false; +} + + +bool Type_handler_bit:: + Item_func_round_fix_length_and_dec(Item_func_round *item) const +{ + uint nbits= item->arguments()[0]->max_length; + item->fix_length_and_dec_ulong_or_ulonglong_by_nbits(nbits); + return false; +} + + +bool Type_handler_typelib:: + Item_func_round_fix_length_and_dec(Item_func_round *item) const +{ + item->fix_length_and_dec_long_or_longlong(5, true); return false; } @@ -6164,10 +6219,12 @@ bool Type_handler_decimal_result:: } -bool Type_handler_temporal_result:: +bool Type_handler_date_common:: Item_func_round_fix_length_and_dec(Item_func_round *item) const { - item->fix_arg_double(); + static const Type_std_attributes attr(Type_numeric_attributes(8, 0, true), + DTCollation_numeric()); + item->fix_arg_int(&type_handler_ulong, &attr); return false; } @@ -6217,7 +6274,43 @@ bool Type_handler_row:: bool Type_handler_int_result:: Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const { - item->fix_length_and_dec_int_or_decimal(); + item->Type_std_attributes::set(item->arguments()[0]); + item->set_handler(this); + return false; +} + + +bool Type_handler_year:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + item->Type_std_attributes::set(item->arguments()[0]); + item->set_handler(&type_handler_ulong); + return false; +} + + +bool Type_handler_bit:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + uint nbits= item->arguments()[0]->max_length; + item->fix_length_and_dec_ulong_or_ulonglong_by_nbits(nbits); + return false; +} + + +bool Type_handler_typelib:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + item->fix_length_and_dec_long_or_longlong(5, true); + return false; +} + + +bool Type_handler_hex_hybrid:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + uint nchars= item->arguments()[0]->decimal_precision(); + item->fix_length_and_dec_long_or_longlong(nchars, true); return false; } @@ -6238,10 +6331,36 @@ bool Type_handler_decimal_result:: } -bool Type_handler_temporal_result:: +bool Type_handler_date_common:: Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const { - item->fix_length_and_dec_int_or_decimal(); + static const Type_numeric_attributes attr(8, 0/*dec*/, true/*unsigned*/); + item->Type_std_attributes::set(attr, DTCollation_numeric()); + item->set_handler(&type_handler_ulong); + return false; +} + + +bool Type_handler_time_common:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + item->fix_length_and_dec_time(); + return false; +} + + +bool Type_handler_datetime_common:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + item->fix_length_and_dec_datetime(); + return false; +} + + +bool Type_handler_timestamp_common:: + Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const +{ + item->fix_length_and_dec_datetime(); return false; } @@ -8589,7 +8708,8 @@ static void literal_warn(THD *thd, const Item *item, ErrConvString err(str, length, cs); thd->push_warning_wrong_or_truncated_value( Sql_condition::time_warn_level(st->warnings), - false, typestr, err.ptr(), NULL, NullS); + false, typestr, err.ptr(), + nullptr, nullptr, nullptr); } } else if (send_error) diff --git a/sql/sql_type.h b/sql/sql_type.h index dcff53eb4f1..ed0aaaea400 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -807,34 +807,39 @@ public: public: void push_conversion_warnings(THD *thd, bool totally_useless_value, date_mode_t mode, timestamp_type tstype, - const TABLE_SHARE* s, const char *name) + const char *db_name, const char *table_name, + const char *name) { const char *typestr= tstype >= 0 ? type_name_by_timestamp_type(tstype) : mode & (TIME_INTERVAL_hhmmssff | TIME_INTERVAL_DAY) ? "interval" : mode & TIME_TIME_ONLY ? "time" : "datetime"; Temporal::push_conversion_warnings(thd, totally_useless_value, warnings, - typestr, s, name, ptr()); + typestr, db_name, table_name, name, + ptr()); } }; class Warn_push: public Warn { - THD *m_thd; - const TABLE_SHARE *m_s; - const char *m_name; - const MYSQL_TIME *m_ltime; - date_mode_t m_mode; + THD * const m_thd; + const char * const m_db_name; + const char * const m_table_name; + const char * const m_name; + const MYSQL_TIME * const m_ltime; + const date_mode_t m_mode; public: - Warn_push(THD *thd, const TABLE_SHARE *s, const char *name, - const MYSQL_TIME *ltime, date_mode_t mode) - :m_thd(thd), m_s(s), m_name(name), m_ltime(ltime), m_mode(mode) + Warn_push(THD *thd, const char *db_name, const char *table_name, + const char *name, const MYSQL_TIME *ltime, date_mode_t mode) + : m_thd(thd), m_db_name(db_name), m_table_name(table_name), m_name(name), + m_ltime(ltime), m_mode(mode) { } ~Warn_push() { if (warnings) push_conversion_warnings(m_thd, m_ltime->time_type < 0, - m_mode, m_ltime->time_type, m_s, m_name); + m_mode, m_ltime->time_type, + m_db_name, m_table_name, m_name); } }; @@ -875,7 +880,8 @@ public: } static void push_conversion_warnings(THD *thd, bool totally_useless_value, int warn, const char *type_name, - const TABLE_SHARE *s, + const char *db_name, + const char *table_name, const char *field_name, const char *value); /* @@ -1503,6 +1509,14 @@ public: { } }; + class Options_for_round: public Options + { + public: + Options_for_round(time_round_mode_t round_mode= TIME_FRAC_TRUNCATE) + :Options(Time::default_flags_for_get_date(), round_mode, + Time::DATETIME_TO_TIME_DISALLOW) + { } + }; class Options_cmp: public Options { public: @@ -1854,6 +1868,40 @@ public: DBUG_ASSERT(is_valid_value_slow()); return *this; } + Time &ceiling(int *warn) + { + if (is_valid_time()) + { + if (neg) + my_time_trunc(this, 0); + else if (second_part) + round_or_set_max(0, warn, 999999999); + } + DBUG_ASSERT(is_valid_value_slow()); + return *this; + } + Time &ceiling() + { + int warn= 0; + return ceiling(&warn); + } + Time &floor(int *warn) + { + if (is_valid_time()) + { + if (!neg) + my_time_trunc(this, 0); + else if (second_part) + round_or_set_max(0, warn, 999999999); + } + DBUG_ASSERT(is_valid_value_slow()); + return *this; + } + Time &floor() + { + int warn= 0; + return floor(&warn); + } Time &round(uint dec, int *warn) { if (is_valid_time()) @@ -2421,10 +2469,22 @@ public: Datetime &trunc(uint dec) { if (is_valid_datetime()) - my_time_trunc(this, dec); + my_datetime_trunc(this, dec); + DBUG_ASSERT(is_valid_value_slow()); + return *this; + } + Datetime &ceiling(THD *thd, int *warn) + { + if (is_valid_datetime() && second_part) + round_or_invalidate(thd, 0, warn, 999999999); DBUG_ASSERT(is_valid_value_slow()); return *this; } + Datetime &ceiling(THD *thd) + { + int warn= 0; + return ceiling(thd, &warn); + } Datetime &round(THD *thd, uint dec, int *warn) { if (is_valid_datetime()) @@ -5102,8 +5162,6 @@ public: bool Item_func_between_fix_length_and_dec(Item_func_between *)const override; bool Item_func_in_fix_comparator_compatible_types(THD *, Item_func_in *) const override; - bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; - bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *)const override; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override; bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override; @@ -5629,6 +5687,8 @@ public: const Column_definition_attributes *attr, uint32 flags) const override; Item_cache *Item_get_cache(THD *thd, const Item *item) const override; + bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *)const override; void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn, MYSQL_TIME *ltime, date_mode_t fuzzydate) const override; void Item_func_hybrid_field_type_get_date(THD *, @@ -5653,7 +5713,7 @@ public: } uint32 max_display_length(const Item *item) const override; uint32 Item_decimal_notation_int_digits(const Item *item) const override; - static uint32 Bit_decimal_notation_int_digits(const Item *item); + static uint32 Bit_decimal_notation_int_digits_by_nbits(uint nbits); uint32 max_display_length_for_field(const Conv_source &src) const override; uint32 calc_pack_length(uint32 length) const override { return length / 8; } uint calc_key_length(const Column_definition &def) const override; @@ -5670,6 +5730,8 @@ public: } void show_binlog_type(const Conv_source &src, const Field &, String *str) const override; + bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, const Field *target) const override; @@ -5912,6 +5974,7 @@ public: const override; longlong Item_func_between_val_int(Item_func_between *func) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const override; bool set_comparator_func(Arg_comparator *cmp) const override; @@ -6073,6 +6136,8 @@ public: longlong Item_func_min_max_val_int(Item_func_min_max *) const override; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override; + bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, Type_handler_hybrid_field_type *, @@ -6208,6 +6273,7 @@ public: String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override; double Item_func_min_max_val_real(Item_func_min_max *) const override; longlong Item_func_min_max_val_int(Item_func_min_max *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; @@ -6337,6 +6403,7 @@ public: int cmp_native(const Native &a, const Native &b) const override; longlong Item_func_between_val_int(Item_func_between *func) const override; bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override; in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const override; @@ -6762,6 +6829,8 @@ class Type_handler_hex_hybrid: public Type_handler_varchar public: virtual ~Type_handler_hex_hybrid() {} const Type_handler *cast_to_int_type_handler() const override; + bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; }; @@ -6980,6 +7049,8 @@ public: enum_field_types field_type() const override { return MYSQL_TYPE_STRING; } const Type_handler *type_handler_for_item_field() const override; const Type_handler *cast_to_int_type_handler() const override; + bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val*) const override; uint32 max_display_length_for_field(const Conv_source &src) const override; bool Item_hybrid_func_fix_attributes(THD *thd, const char *name, diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index f08b9733e89..4bda42b2ffa 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3863,6 +3863,12 @@ static bool fix_tp_min_threads(sys_var *, THD *, enum_var_type) static bool check_threadpool_size(sys_var *self, THD *thd, set_var *var) { + +#ifdef _WIN32 + if (threadpool_mode != TP_MODE_GENERIC) + return false; +#endif + ulonglong v= var->save_result.ulonglong_value; if (v > threadpool_max_size) { diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index ed2aaf49b9f..ba56a7b4bfb 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -534,7 +534,10 @@ public: String str2(buff2, sizeof(buff2), charset), *res; if (!(res=var->value->val_str(&str))) + { var->save_result.string_value.str= 0; + var->save_result.string_value.length= 0; // safety + } else { uint32 unused; @@ -939,9 +942,16 @@ public: String str(buff, sizeof(buff), system_charset_info), *res; if (!(res=var->value->val_str(&str))) + { var->save_result.string_value.str= const_cast<char*>(""); + var->save_result.string_value.length= 0; + } else - var->save_result.string_value.str= thd->strmake(res->ptr(), res->length()); + { + size_t len= res->length(); + var->save_result.string_value.str= thd->strmake(res->ptr(), len); + var->save_result.string_value.length= len; + } return false; } bool session_update(THD *thd, set_var *var) @@ -965,6 +975,7 @@ public: { char *ptr= (char*)(intptr)option.def_value; var->save_result.string_value.str= ptr; + var->save_result.string_value.length= safe_strlen(ptr); } uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) { diff --git a/sql/table.cc b/sql/table.cc index d7ea9d447fa..e4ed862f41b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -50,6 +50,17 @@ #define MYSQL57_GENERATED_FIELD 128 #define MYSQL57_GCOL_HEADER_SIZE 4 +class Table_arena: public Query_arena +{ +public: + Table_arena(MEM_ROOT *mem_root, enum enum_state state_arg) : + Query_arena(mem_root, state_arg){} + virtual Type type() const + { + return TABLE_ARENA; + } +}; + struct extra2_fields { LEX_CUSTRING version; @@ -1145,8 +1156,9 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table, We need to use CONVENTIONAL_EXECUTION here to ensure that any new items created by fix_fields() are not reverted. */ - table->expr_arena= new (alloc_root(mem_root, sizeof(Query_arena))) - Query_arena(mem_root, Query_arena::STMT_CONVENTIONAL_EXECUTION); + table->expr_arena= new (alloc_root(mem_root, sizeof(Table_arena))) + Table_arena(mem_root, + Query_arena::STMT_CONVENTIONAL_EXECUTION); if (!table->expr_arena) DBUG_RETURN(1); diff --git a/sql/table.h b/sql/table.h index f719a0d03a2..6f3620de83f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1667,6 +1667,7 @@ public: TABLE *tmp_table, TMP_TABLE_PARAM *tmp_table_param, bool with_cleanup); + int fix_vcol_exprs(THD *thd); Field *find_field_by_name(LEX_CSTRING *str) const; bool export_structure(THD *thd, class Row_definition_list *defs); bool is_splittable() { return spl_opt_info != NULL; } diff --git a/sql/threadpool.h b/sql/threadpool.h index b781e50b992..27da872c5cc 100644 --- a/sql/threadpool.h +++ b/sql/threadpool.h @@ -74,6 +74,7 @@ enum TP_STATE { TP_STATE_IDLE, TP_STATE_RUNNING, + TP_STATE_PENDING }; /* diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc index bd8573951b6..877428e67ac 100644 --- a/sql/threadpool_common.cc +++ b/sql/threadpool_common.cc @@ -451,11 +451,25 @@ void tp_timeout_handler(TP_connection *c) { if (c->state != TP_STATE_IDLE) return; - THD *thd=c->thd; + THD *thd= c->thd; mysql_mutex_lock(&thd->LOCK_thd_kill); - thd->set_killed_no_mutex(KILL_WAIT_TIMEOUT); - c->priority= TP_PRIORITY_HIGH; - post_kill_notification(thd); + Vio *vio= thd->net.vio; + if (vio && (vio_pending(vio) > 0 || vio->has_data(vio)) && + c->state == TP_STATE_IDLE) + { + /* + There is some data on that connection, i.e + i.e there was no inactivity timeout. + Don't kill. + */ + c->state= TP_STATE_PENDING; + } + else if (c->state == TP_STATE_IDLE) + { + thd->set_killed_no_mutex(KILL_WAIT_TIMEOUT); + c->priority= TP_PRIORITY_HIGH; + post_kill_notification(thd); + } mysql_mutex_unlock(&thd->LOCK_thd_kill); } diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc index d9286602ace..7b13803a5c3 100644 --- a/sql/threadpool_generic.cc +++ b/sql/threadpool_generic.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Monty Program Ab +/* Copyright (C) 2012, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -513,11 +513,21 @@ static my_bool timeout_check(THD *thd, pool_timer_t *timer) DBUG_ENTER("timeout_check"); if (thd->net.reading_or_writing == 1) { - /* - Check if connection does not have scheduler data. This happens for example - if THD belongs to a different scheduler, that is listening to extra_port. - */ - if (auto connection= (TP_connection_generic *) thd->event_scheduler.data) + TP_connection_generic *connection= (TP_connection_generic *)thd->event_scheduler.data; + if (!connection || connection->state != TP_STATE_IDLE) + { + /* + Connection does not have scheduler data. This happens for example + if THD belongs to a different scheduler, that is listening to extra_port. + */ + DBUG_RETURN(0); + } + + if(connection->abs_wait_timeout < timer->current_microtime) + { + tp_timeout_handler(connection); + } + else { if (connection->abs_wait_timeout < timer->current_microtime) tp_timeout_handler(connection); diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc index de0aab4b81a..8f52938f9ed 100644 --- a/sql/wsrep_high_priority_service.cc +++ b/sql/wsrep_high_priority_service.cc @@ -292,6 +292,8 @@ int Wsrep_high_priority_service::append_fragment_and_commit( ret= ret || (m_thd->wsrep_cs().after_applying(), 0); m_thd->mdl_context.release_transactional_locks(); + free_root(m_thd->mem_root, MYF(MY_KEEP_PREALLOC)); + thd_proc_info(m_thd, "wsrep applier committed"); DBUG_RETURN(ret); @@ -350,6 +352,8 @@ int Wsrep_high_priority_service::commit(const wsrep::ws_handle& ws_handle, thd->lex->sql_command= SQLCOM_END; + free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC)); + must_exit_= check_exit_status(); DBUG_RETURN(ret); } @@ -370,6 +374,9 @@ int Wsrep_high_priority_service::rollback(const wsrep::ws_handle& ws_handle, int ret= (trans_rollback_stmt(m_thd) || trans_rollback(m_thd)); m_thd->mdl_context.release_transactional_locks(); m_thd->mdl_context.release_explicit_locks(); + + free_root(m_thd->mem_root, MYF(MY_KEEP_PREALLOC)); + DBUG_RETURN(ret); } |