From 216fdb155683e960297b089e024c439593bbe6a8 Mon Sep 17 00:00:00 2001 From: Dave Gosselin Date: Wed, 17 Jul 2024 14:03:19 -0400 Subject: [PATCH 01/17] MDEV-33971 fix --view-protocol test failure Allow the NAME_CONST unwrap optimization when the client is not in the PREPARE step of prepared statement nor in the view analysis mode. --- sql/item.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 0a5c6ff5064..06d64b420db 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2214,8 +2214,9 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref) */ if ((thd->where == THD_WHERE::WHERE_CLAUSE || thd->where == THD_WHERE::ON_CLAUSE) && - (value_item->type() == FUNC_ITEM || - value_item->type() == CONST_ITEM)) + (value_item->type() == CONST_ITEM || + value_item->type() == FUNC_ITEM) && + !thd->lex->is_ps_or_view_context_analysis()) { thd->change_item_tree(ref, value_item); From c91aeb3771cec9475052d8c022a16007322ffccd Mon Sep 17 00:00:00 2001 From: Oleg Smirnov Date: Tue, 23 Jul 2024 15:34:23 +0700 Subject: [PATCH 02/17] MDEV-34634 Types mismatch when cloning items causes debug assertion New runtime diagnostic introduced with MDEV-34490 has detected that `Item_int_with_ref` incorrectly returns an instance of its ancestor class `Item_int`. This commit fixes that. In addition, this commit reverts a part of the diagnostic related to `clone_item()` checks. As it turned out, `clone_item()` is not required to return an object of the same class as the cloned one. For example, look at `Item_param::clone_item()`: it can return objects of `Item_null`, `Item_int`, `Item_string`, etc, depending on the object state. So the runtime type diagnostic is not applicable to `clone_item()` and is disabled with this commit. As the similar diagnostic failures are expected to appear again in the future, this commit introduces a new test file in the main suite: item_types.test, and new test cases may be added to this file Reviewer: Oleksandr Byelkin --- mysql-test/main/item_types.result | 16 +++++++++ mysql-test/main/item_types.test | 15 +++++++++ sql/item.cc | 24 ++++++------- sql/item.h | 56 ++++++++++++++----------------- sql/sql_select.cc | 4 +-- 5 files changed, 71 insertions(+), 44 deletions(-) create mode 100644 mysql-test/main/item_types.result create mode 100644 mysql-test/main/item_types.test diff --git a/mysql-test/main/item_types.result b/mysql-test/main/item_types.result new file mode 100644 index 00000000000..865b4f612ae --- /dev/null +++ b/mysql-test/main/item_types.result @@ -0,0 +1,16 @@ +# +# MDEV-34634 Types mismatch when cloning items causes debug assertion +# +CREATE TABLE t1 (a DATETIME); +SET optimizer_switch='derived_merge=off'; +SELECT * FROM (SELECT * FROM t1) AS t1 WHERE a=''; +a +Warnings: +Warning 1292 Truncated incorrect datetime value: '' +DROP TABLE t1; +CREATE TABLE t1 (c YEAR); +CREATE TABLE t2 (c INT); +SELECT * FROM t1 JOIN t2 ON t1.c=t2.c WHERE t1.c<=>5; +c c +DROP TABLE t1, t2; +SET optimizer_switch=default; diff --git a/mysql-test/main/item_types.test b/mysql-test/main/item_types.test new file mode 100644 index 00000000000..f43bfe1a8ac --- /dev/null +++ b/mysql-test/main/item_types.test @@ -0,0 +1,15 @@ +--echo # +--echo # MDEV-34634 Types mismatch when cloning items causes debug assertion +--echo # + +CREATE TABLE t1 (a DATETIME); +SET optimizer_switch='derived_merge=off'; +SELECT * FROM (SELECT * FROM t1) AS t1 WHERE a=''; +DROP TABLE t1; + +CREATE TABLE t1 (c YEAR); +CREATE TABLE t2 (c INT); +SELECT * FROM t1 JOIN t2 ON t1.c=t2.c WHERE t1.c<=>5; +DROP TABLE t1, t2; + +SET optimizer_switch=default; diff --git a/sql/item.cc b/sql/item.cc index 9ba00944c85..35d7eaefd01 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3847,7 +3847,7 @@ void Item_decimal::set_decimal_value(my_decimal *value_par) } -Item *Item_decimal::do_clone_const_item(THD *thd) const +Item *Item_decimal::clone_item(THD *thd) const { return new (thd->mem_root) Item_decimal(thd, name.str, &decimal_value, decimals, max_length); @@ -3868,7 +3868,7 @@ my_decimal *Item_float::val_decimal(my_decimal *decimal_value) } -Item *Item_float::do_clone_const_item(THD *thd) const +Item *Item_float::clone_item(THD *thd) const { return new (thd->mem_root) Item_float(thd, name.str, value, decimals, max_length); @@ -4032,7 +4032,7 @@ Item *Item_null::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) return this; } -Item *Item_null::do_clone_const_item(THD *thd) const +Item *Item_null::clone_item(THD *thd) const { return new (thd->mem_root) Item_null(thd, name.str); } @@ -4873,7 +4873,7 @@ Item *Item_param::value_clone_item(THD *thd) const /* see comments in the header file */ Item * -Item_param::do_clone_const_item(THD *thd) const +Item_param::clone_item(THD *thd) const { // There's no "default". See comments in Item_param::save_in_field(). switch (state) { @@ -6953,7 +6953,7 @@ int Item_string::save_in_field(Field *field, bool no_conversions) } -Item *Item_string::do_clone_const_item(THD *thd) const +Item *Item_string::clone_item(THD *thd) const { LEX_CSTRING val; str_value.get_value(&val); @@ -7017,7 +7017,7 @@ int Item_int::save_in_field(Field *field, bool no_conversions) } -Item *Item_int::do_clone_const_item(THD *thd) const +Item *Item_int::clone_item(THD *thd) const { return new (thd->mem_root) Item_int(thd, name.str, value, max_length, unsigned_flag); } @@ -7046,7 +7046,7 @@ int Item_decimal::save_in_field(Field *field, bool no_conversions) } -Item *Item_int_with_ref::do_clone_const_item(THD *thd) const +Item *Item_int_with_ref::clone_item(THD *thd) const { DBUG_ASSERT(ref->const_item()); /* @@ -7142,7 +7142,7 @@ Item *Item_uint::neg(THD *thd) } -Item *Item_uint::do_clone_const_item(THD *thd) const +Item *Item_uint::clone_item(THD *thd) const { return new (thd->mem_root) Item_uint(thd, name.str, value, max_length); } @@ -7380,7 +7380,7 @@ void Item_date_literal::print(String *str, enum_query_type query_type) } -Item *Item_date_literal::do_clone_const_item(THD *thd) const +Item *Item_date_literal::clone_item(THD *thd) const { return new (thd->mem_root) Item_date_literal(thd, &cached_time); } @@ -7405,7 +7405,7 @@ void Item_datetime_literal::print(String *str, enum_query_type query_type) } -Item *Item_datetime_literal::do_clone_const_item(THD *thd) const +Item *Item_datetime_literal::clone_item(THD *thd) const { return new (thd->mem_root) Item_datetime_literal(thd, &cached_time, decimals); } @@ -7430,7 +7430,7 @@ void Item_time_literal::print(String *str, enum_query_type query_type) } -Item *Item_time_literal::do_clone_const_item(THD *thd) const +Item *Item_time_literal::clone_item(THD *thd) const { return new (thd->mem_root) Item_time_literal(thd, &cached_time, decimals); } @@ -10389,7 +10389,7 @@ void Item_cache_temporal::store_packed(longlong val_arg, Item *example_arg) } -Item *Item_cache_temporal::do_clone_const_item(THD *thd) const +Item *Item_cache_temporal::clone_item(THD *thd) const { Item_cache *tmp= type_handler()->Item_get_cache(thd, this); Item_cache_temporal *item= static_cast(tmp); diff --git a/sql/item.h b/sql/item.h index 19f95c5875f..b531647e8bf 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1698,21 +1698,17 @@ public: } /* - Clones the constant item + Clones the constant item (not necessary returning the same item type) Return value: - pointer to a clone of the Item - - nullptr if the item is not clonable */ - Item *clone_const_item(THD *thd) const - { - Item *clone= do_clone_const_item(thd); - if (clone) - { - // Make sure the clone is of same type as this item - DBUG_ASSERT(typeid(*clone) == typeid(*this)); - } - return clone; - } + - nullptr if the item is not clonable + + Note: the clone may have item type different from this + (i.e., instance of another basic constant class may be returned). + For real clones look at build_clone()/get_copy() methods + */ + virtual Item *clone_item(THD *thd) const { return nullptr; } virtual cond_result eq_cmp_result() const { return COND_OK; } inline uint float_length(uint decimals_par) const @@ -2588,12 +2584,6 @@ protected: deep copies (clones) of the item where possible */ virtual Item* do_build_clone(THD *thd) const = 0; - - /* - Service function for public method clone_const_item(). See comments for - clone_const_item() above - */ - virtual Item *do_clone_const_item(THD *thd) const { return nullptr; } }; MEM_ROOT *get_thd_memroot(THD *thd); @@ -3820,7 +3810,7 @@ public: const Type_handler *type_handler() const override { return &type_handler_null; } bool basic_const_item() const override { return true; } - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; bool const_is_null() const override { return true; } bool is_null() override { return true; } @@ -4270,7 +4260,7 @@ public: basic_const_item returned TRUE. */ Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; void set_param_type_and_swap_value(Item_param *from); Rewritable_query_parameter *get_rewritable_query_parameter() override @@ -4369,7 +4359,7 @@ public: String *val_str(String*) override; int save_in_field(Field *field, bool no_conversions) override; bool is_order_clause_position() const override { return true; } - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; void print(String *str, enum_query_type query_type) override; Item *neg(THD *thd) override; uint decimal_precision() const override @@ -4417,7 +4407,7 @@ public: Item_uint(THD *thd, ulonglong i): Item_int(thd, i, 10) {} Item_uint(THD *thd, const char *str_arg, longlong i, uint length); double val_real() override { return ulonglong2double((ulonglong)value); } - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; Item *neg(THD *thd) override; uint decimal_precision() const override { return max_length; } Item *do_get_copy(THD *thd) const override @@ -4468,7 +4458,7 @@ public: const my_decimal *const_ptr_my_decimal() const override { return &decimal_value; } int save_in_field(Field *field, bool no_conversions) override; - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; void print(String *str, enum_query_type query_type) override { decimal_value.to_string(&str_value); @@ -4521,7 +4511,7 @@ public: } String *val_str(String*) override; my_decimal *val_decimal(my_decimal *) override; - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; Item *neg(THD *thd) override; void print(String *str, enum_query_type query_type) override; Item *do_get_copy(THD *thd) const override @@ -4644,7 +4634,7 @@ public: int save_in_field(Field *field, bool no_conversions) override; const Type_handler *type_handler() const override { return &type_handler_varchar; } - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override { return const_charset_converter(thd, tocs, true); @@ -5067,7 +5057,7 @@ public: { return cached_time.get_mysql_time(); } - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; longlong val_int() override { return update_null() ? 0 : cached_time.to_longlong(); @@ -5117,7 +5107,7 @@ public: { return cached_time.get_mysql_time(); } - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; longlong val_int() override { return cached_time.to_longlong(); } double val_real() override { return cached_time.to_double(); } String *val_str(String *to) override @@ -5168,7 +5158,7 @@ public: { return cached_time.get_mysql_time(); } - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; longlong val_int() override { return update_null() ? 0 : cached_time.to_longlong(); @@ -5256,6 +5246,9 @@ public: cached_time.copy_to_mysql_time(ltime); return (null_value= false); } + Item *do_get_copy(THD *thd) const override + { return get_item_copy(thd, this); } + Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; @@ -6299,8 +6292,11 @@ public: { return ref->save_in_field(field, no_conversions); } - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; Item *real_item() override { return ref; } + Item *do_get_copy(THD *thd) const override + { return get_item_copy(thd, this); } + Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; #ifdef MYSQL_SERVER @@ -7209,7 +7205,7 @@ public: is a constant and need not be optimized further. Important when storing packed datetime values. */ - Item *do_clone_const_item(THD *thd) const override; + Item *clone_item(THD *thd) const override; Item *convert_to_basic_const_item(THD *thd) override; virtual Item *make_literal(THD *) =0; }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 92f0a8fa578..b86ffed8619 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -16632,7 +16632,7 @@ change_cond_ref_to_const(THD *thd, I_List *save_list, if (can_change_cond_ref_to_const(func, right_item, left_item, field_value_owner, field, value)) { - Item *tmp=value->clone_const_item(thd); + Item *tmp=value->clone_item(thd); if (tmp) { tmp->collation.set(right_item->collation); @@ -16662,7 +16662,7 @@ change_cond_ref_to_const(THD *thd, I_List *save_list, else if (can_change_cond_ref_to_const(func, left_item, right_item, field_value_owner, field, value)) { - Item *tmp= value->clone_const_item(thd); + Item *tmp= value->clone_item(thd); if (tmp) { tmp->collation.set(left_item->collation); From 3359ac09a42c26cbf9002da268cbc949721464b8 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 23 Jul 2024 21:35:27 +0530 Subject: [PATCH 03/17] MDEV-34066 Output of SHOW ENGINE INNODB STATUS uses the nanoseconds suffix for microseconds - This issue is caused by commit e71e6133535da8d5eab86e504f0b116a03680780 (MDEV-24671). Change the output of transaction lock wait time in microseconds suffix. --- storage/innobase/lock/lock0lock.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index d1f1ec0c85a..ea67e4a895f 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -5015,7 +5015,7 @@ void lock_trx_print_wait_and_mvcc_state(FILE *file, const trx_t *trx, if (const lock_t* wait_lock = trx->lock.wait_lock) { const my_hrtime_t suspend_time= trx->lock.suspend_time; fprintf(file, - "------- TRX HAS BEEN WAITING %llu ns" + "------- TRX HAS BEEN WAITING %llu us" " FOR THIS LOCK TO BE GRANTED:\n", now.val - suspend_time.val); From 26f31bdd5261890e705f9bfebf08dec0d552e47e Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 24 Jul 2024 16:41:29 +0200 Subject: [PATCH 04/17] The test should be not for AddressSanitizer used becouse stack check tests and this check switched off --- ...ug_nonembedded.result => json_debug_nonembedded_noasan.result} | 0 ..._debug_nonembedded.test => json_debug_nonembedded_noasan.test} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename mysql-test/main/{json_debug_nonembedded.result => json_debug_nonembedded_noasan.result} (100%) rename mysql-test/main/{json_debug_nonembedded.test => json_debug_nonembedded_noasan.test} (100%) diff --git a/mysql-test/main/json_debug_nonembedded.result b/mysql-test/main/json_debug_nonembedded_noasan.result similarity index 100% rename from mysql-test/main/json_debug_nonembedded.result rename to mysql-test/main/json_debug_nonembedded_noasan.result diff --git a/mysql-test/main/json_debug_nonembedded.test b/mysql-test/main/json_debug_nonembedded_noasan.test similarity index 100% rename from mysql-test/main/json_debug_nonembedded.test rename to mysql-test/main/json_debug_nonembedded_noasan.test From 7788593547c557657d3d081d397cfddb515226df Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 14 Jun 2024 14:05:48 +1000 Subject: [PATCH 05/17] MDEV-19052 Range-type window frame supports only numeric datatype When there is no bounds on the upper or lower part of the window, it doesn't matter if the type is numeric. It also doesn't matter how many ORDER BY items there are in the query. Reviewers: Sergei Petrunia and Oleg Smirnov --- mysql-test/main/win.result | 60 +++++++++++++++++-- mysql-test/main/win.test | 46 +++++++++++--- .../encryption/r/tempfiles_encrypted.result | 60 +++++++++++++++++-- sql/sql_window.cc | 5 +- 4 files changed, 151 insertions(+), 20 deletions(-) diff --git a/mysql-test/main/win.result b/mysql-test/main/win.result index 533173797b5..cf51315f612 100644 --- a/mysql-test/main/win.result +++ b/mysql-test/main/win.result @@ -1247,15 +1247,10 @@ insert into t1 values (1,1,'foo'); insert into t1 values (2,2,'bar'); select count(*) over (order by a,b -range between unbounded preceding and current row) as count +range between 1 preceding and current row) as count from t1; ERROR HY000: RANGE-type frame requires ORDER BY clause with single sort key select -count(*) over (order by c -range between unbounded preceding and current row) as count -from t1; -ERROR HY000: Numeric datatype is required for RANGE-type frame -select count(*) over (order by a range between 'abcd' preceding and current row) as count from t1; @@ -1277,6 +1272,59 @@ rows between current row and 3.14 following) as count from t1; ERROR HY000: Integer is required for ROWS-type frame # +# MDEV-19052 Range-type window frame supports only numeric datatype +# +select +count(*) over (order by c +range between unbounded preceding and current row) +from t1; +count(*) over (order by c +range between unbounded preceding and current row) +1 +2 +select +count(*) over (order by c +range between current row and unbounded following) +from t1; +count(*) over (order by c +range between current row and unbounded following) +2 +1 +select +count(*) over (order by c +range between unbounded preceding and unbounded following) +from t1; +count(*) over (order by c +range between unbounded preceding and unbounded following) +2 +2 +create table t2 (a int, b varchar(5)); +insert into t2 values (1,'a'), (2, 'b'), (3, 'c'); +select sum(a) over (order by b range between unbounded preceding and current row) from t2; +sum(a) over (order by b range between unbounded preceding and current row) +1 +3 +6 +insert into t1 values (3,3,'goo'); +insert into t1 values (3,1,'har'); +insert into t1 values (1,4,'har'); +select a, b, sum(b) over (order by a, b desc range between unbounded preceding and current row) from t1; +a b sum(b) over (order by a, b desc range between unbounded preceding and current row) +1 4 4 +1 1 5 +2 2 7 +3 3 10 +3 1 11 +select a, b, sum(b) over (order by a desc, b range between unbounded preceding and current row) from t1; +a b sum(b) over (order by a desc, b range between unbounded preceding and current row) +3 1 1 +3 3 4 +2 2 6 +1 1 7 +1 4 11 +drop table t2; +delete from t1 where a >= 3 or b = 4; +# # EXCLUDE clause is parsed but not supported # select diff --git a/mysql-test/main/win.test b/mysql-test/main/win.test index fa2034a145d..d8771f158fe 100644 --- a/mysql-test/main/win.test +++ b/mysql-test/main/win.test @@ -784,13 +784,7 @@ insert into t1 values (2,2,'bar'); --error ER_RANGE_FRAME_NEEDS_SIMPLE_ORDERBY select count(*) over (order by a,b - range between unbounded preceding and current row) as count -from t1; - ---error ER_WRONG_TYPE_FOR_RANGE_FRAME -select - count(*) over (order by c - range between unbounded preceding and current row) as count + range between 1 preceding and current row) as count from t1; --error ER_WRONG_TYPE_FOR_RANGE_FRAME @@ -818,6 +812,41 @@ select rows between current row and 3.14 following) as count from t1; +--echo # +--echo # MDEV-19052 Range-type window frame supports only numeric datatype +--echo # + +select + count(*) over (order by c + range between unbounded preceding and current row) +from t1; + +select + count(*) over (order by c + range between current row and unbounded following) +from t1; + +select + count(*) over (order by c + range between unbounded preceding and unbounded following) +from t1; + +create table t2 (a int, b varchar(5)); +insert into t2 values (1,'a'), (2, 'b'), (3, 'c'); + +select sum(a) over (order by b range between unbounded preceding and current row) from t2; + +insert into t1 values (3,3,'goo'); +insert into t1 values (3,1,'har'); +insert into t1 values (1,4,'har'); + +select a, b, sum(b) over (order by a, b desc range between unbounded preceding and current row) from t1; + +select a, b, sum(b) over (order by a desc, b range between unbounded preceding and current row) from t1; + +drop table t2; +delete from t1 where a >= 3 or b = 4; + --echo # --echo # EXCLUDE clause is parsed but not supported --echo # @@ -843,6 +872,9 @@ select exclude group) as count from t1; + + + # EXCLUDE NO OTHERS means 'don't exclude anything' select count(*) over (order by a diff --git a/mysql-test/suite/encryption/r/tempfiles_encrypted.result b/mysql-test/suite/encryption/r/tempfiles_encrypted.result index 67347191261..edf7acba24f 100644 --- a/mysql-test/suite/encryption/r/tempfiles_encrypted.result +++ b/mysql-test/suite/encryption/r/tempfiles_encrypted.result @@ -1253,15 +1253,10 @@ insert into t1 values (1,1,'foo'); insert into t1 values (2,2,'bar'); select count(*) over (order by a,b -range between unbounded preceding and current row) as count +range between 1 preceding and current row) as count from t1; ERROR HY000: RANGE-type frame requires ORDER BY clause with single sort key select -count(*) over (order by c -range between unbounded preceding and current row) as count -from t1; -ERROR HY000: Numeric datatype is required for RANGE-type frame -select count(*) over (order by a range between 'abcd' preceding and current row) as count from t1; @@ -1283,6 +1278,59 @@ rows between current row and 3.14 following) as count from t1; ERROR HY000: Integer is required for ROWS-type frame # +# MDEV-19052 Range-type window frame supports only numeric datatype +# +select +count(*) over (order by c +range between unbounded preceding and current row) +from t1; +count(*) over (order by c +range between unbounded preceding and current row) +1 +2 +select +count(*) over (order by c +range between current row and unbounded following) +from t1; +count(*) over (order by c +range between current row and unbounded following) +2 +1 +select +count(*) over (order by c +range between unbounded preceding and unbounded following) +from t1; +count(*) over (order by c +range between unbounded preceding and unbounded following) +2 +2 +create table t2 (a int, b varchar(5)); +insert into t2 values (1,'a'), (2, 'b'), (3, 'c'); +select sum(a) over (order by b range between unbounded preceding and current row) from t2; +sum(a) over (order by b range between unbounded preceding and current row) +1 +3 +6 +insert into t1 values (3,3,'goo'); +insert into t1 values (3,1,'har'); +insert into t1 values (1,4,'har'); +select a, b, sum(b) over (order by a, b desc range between unbounded preceding and current row) from t1; +a b sum(b) over (order by a, b desc range between unbounded preceding and current row) +1 4 4 +1 1 5 +2 2 7 +3 3 10 +3 1 11 +select a, b, sum(b) over (order by a desc, b range between unbounded preceding and current row) from t1; +a b sum(b) over (order by a desc, b range between unbounded preceding and current row) +3 1 1 +3 3 4 +2 2 6 +1 1 7 +1 4 11 +drop table t2; +delete from t1 where a >= 3 or b = 4; +# # EXCLUDE clause is parsed but not supported # select diff --git a/sql/sql_window.cc b/sql/sql_window.cc index 2be6059f2a1..fd8e188a76b 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -262,9 +262,12 @@ setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, For "win_func() OVER (ORDER BY order_list RANGE BETWEEN ...)", - ORDER BY order_list must not be ommitted - the list must have a single element. + But it really only matters if the frame is bounded. */ if (win_spec->window_frame && - win_spec->window_frame->units == Window_frame::UNITS_RANGE) + win_spec->window_frame->units == Window_frame::UNITS_RANGE && + !(win_spec->window_frame->top_bound->is_unbounded() && + win_spec->window_frame->bottom_bound->is_unbounded())) { if (win_spec->order_list->elements != 1) { From 0939bfc093ef8c1ae553f5d2bdbdf56ced97d149 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sat, 27 Jul 2024 12:52:51 +1000 Subject: [PATCH 06/17] MDEV-19052 main.win postfix --view-protocol compat Correct compatibility with view-protocol. Thanks Lena Startseva --- mysql-test/main/win.result | 27 +++++++++---------- mysql-test/main/win.test | 12 ++++----- .../encryption/r/tempfiles_encrypted.result | 27 +++++++++---------- 3 files changed, 30 insertions(+), 36 deletions(-) diff --git a/mysql-test/main/win.result b/mysql-test/main/win.result index cf51315f612..f3b719d0a18 100644 --- a/mysql-test/main/win.result +++ b/mysql-test/main/win.result @@ -1276,47 +1276,44 @@ ERROR HY000: Integer is required for ROWS-type frame # select count(*) over (order by c -range between unbounded preceding and current row) +range between unbounded preceding and current row) as r from t1; -count(*) over (order by c -range between unbounded preceding and current row) +r 1 2 select count(*) over (order by c -range between current row and unbounded following) +range between current row and unbounded following) as r from t1; -count(*) over (order by c -range between current row and unbounded following) +r 2 1 select count(*) over (order by c -range between unbounded preceding and unbounded following) +range between unbounded preceding and unbounded following) as r from t1; -count(*) over (order by c -range between unbounded preceding and unbounded following) +r 2 2 create table t2 (a int, b varchar(5)); insert into t2 values (1,'a'), (2, 'b'), (3, 'c'); -select sum(a) over (order by b range between unbounded preceding and current row) from t2; -sum(a) over (order by b range between unbounded preceding and current row) +select sum(a) over (order by b range between unbounded preceding and current row) as r from t2; +r 1 3 6 insert into t1 values (3,3,'goo'); insert into t1 values (3,1,'har'); insert into t1 values (1,4,'har'); -select a, b, sum(b) over (order by a, b desc range between unbounded preceding and current row) from t1; -a b sum(b) over (order by a, b desc range between unbounded preceding and current row) +select a, b, sum(b) over (order by a, b desc range between unbounded preceding and current row) as r from t1; +a b r 1 4 4 1 1 5 2 2 7 3 3 10 3 1 11 -select a, b, sum(b) over (order by a desc, b range between unbounded preceding and current row) from t1; -a b sum(b) over (order by a desc, b range between unbounded preceding and current row) +select a, b, sum(b) over (order by a desc, b range between unbounded preceding and current row) as r from t1; +a b r 3 1 1 3 3 4 2 2 6 diff --git a/mysql-test/main/win.test b/mysql-test/main/win.test index d8771f158fe..5722cedab81 100644 --- a/mysql-test/main/win.test +++ b/mysql-test/main/win.test @@ -818,31 +818,31 @@ from t1; select count(*) over (order by c - range between unbounded preceding and current row) + range between unbounded preceding and current row) as r from t1; select count(*) over (order by c - range between current row and unbounded following) + range between current row and unbounded following) as r from t1; select count(*) over (order by c - range between unbounded preceding and unbounded following) + range between unbounded preceding and unbounded following) as r from t1; create table t2 (a int, b varchar(5)); insert into t2 values (1,'a'), (2, 'b'), (3, 'c'); -select sum(a) over (order by b range between unbounded preceding and current row) from t2; +select sum(a) over (order by b range between unbounded preceding and current row) as r from t2; insert into t1 values (3,3,'goo'); insert into t1 values (3,1,'har'); insert into t1 values (1,4,'har'); -select a, b, sum(b) over (order by a, b desc range between unbounded preceding and current row) from t1; +select a, b, sum(b) over (order by a, b desc range between unbounded preceding and current row) as r from t1; -select a, b, sum(b) over (order by a desc, b range between unbounded preceding and current row) from t1; +select a, b, sum(b) over (order by a desc, b range between unbounded preceding and current row) as r from t1; drop table t2; delete from t1 where a >= 3 or b = 4; diff --git a/mysql-test/suite/encryption/r/tempfiles_encrypted.result b/mysql-test/suite/encryption/r/tempfiles_encrypted.result index edf7acba24f..e233c8fa3ef 100644 --- a/mysql-test/suite/encryption/r/tempfiles_encrypted.result +++ b/mysql-test/suite/encryption/r/tempfiles_encrypted.result @@ -1282,47 +1282,44 @@ ERROR HY000: Integer is required for ROWS-type frame # select count(*) over (order by c -range between unbounded preceding and current row) +range between unbounded preceding and current row) as r from t1; -count(*) over (order by c -range between unbounded preceding and current row) +r 1 2 select count(*) over (order by c -range between current row and unbounded following) +range between current row and unbounded following) as r from t1; -count(*) over (order by c -range between current row and unbounded following) +r 2 1 select count(*) over (order by c -range between unbounded preceding and unbounded following) +range between unbounded preceding and unbounded following) as r from t1; -count(*) over (order by c -range between unbounded preceding and unbounded following) +r 2 2 create table t2 (a int, b varchar(5)); insert into t2 values (1,'a'), (2, 'b'), (3, 'c'); -select sum(a) over (order by b range between unbounded preceding and current row) from t2; -sum(a) over (order by b range between unbounded preceding and current row) +select sum(a) over (order by b range between unbounded preceding and current row) as r from t2; +r 1 3 6 insert into t1 values (3,3,'goo'); insert into t1 values (3,1,'har'); insert into t1 values (1,4,'har'); -select a, b, sum(b) over (order by a, b desc range between unbounded preceding and current row) from t1; -a b sum(b) over (order by a, b desc range between unbounded preceding and current row) +select a, b, sum(b) over (order by a, b desc range between unbounded preceding and current row) as r from t1; +a b r 1 4 4 1 1 5 2 2 7 3 3 10 3 1 11 -select a, b, sum(b) over (order by a desc, b range between unbounded preceding and current row) from t1; -a b sum(b) over (order by a desc, b range between unbounded preceding and current row) +select a, b, sum(b) over (order by a desc, b range between unbounded preceding and current row) as r from t1; +a b r 3 1 1 3 3 4 2 2 6 From 232d7a5e2dc50181294b927e2bc4b02e282725a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 29 Jul 2024 10:58:09 +0300 Subject: [PATCH 07/17] MDEV-34565: SIGILL due to OS not supporting AVX512 It is not sufficient to check that the CPU supports the necessary instructions. Also the operating system (or virtual machine hypervisor) must enable all the AVX registers to be saved and restored on a context switch. Because clang 8 does not support the compiler intrinsic _xgetbv() we will require clang 9 or later for enabling the use of VPCLMULQDQ and the related AVX512 features. --- mysys/crc32/crc32c_x86.cc | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/mysys/crc32/crc32c_x86.cc b/mysys/crc32/crc32c_x86.cc index 0a4fd9db812..3ddddf1303c 100644 --- a/mysys/crc32/crc32c_x86.cc +++ b/mysys/crc32/crc32c_x86.cc @@ -28,7 +28,8 @@ # elif __GNUC__ >= 14 || (defined __clang_major__ && __clang_major__ >= 18) # define TARGET "pclmul,evex512,avx512f,avx512dq,avx512bw,avx512vl,vpclmulqdq" # define USE_VPCLMULQDQ __attribute__((target(TARGET))) -# elif __GNUC__ >= 11 || (defined __clang_major__ && __clang_major__ >= 8) +# elif __GNUC__ >= 11 || (defined __clang_major__ && __clang_major__ >= 9) +/* clang 8 does not support _xgetbv(), which we also need */ # define TARGET "pclmul,avx512f,avx512dq,avx512bw,avx512vl,vpclmulqdq" # define USE_VPCLMULQDQ __attribute__((target(TARGET))) # endif @@ -38,6 +39,7 @@ extern "C" unsigned crc32c_sse42(unsigned crc, const void* buf, size_t size); constexpr uint32_t cpuid_ecx_SSE42= 1U << 20; constexpr uint32_t cpuid_ecx_SSE42_AND_PCLMUL= cpuid_ecx_SSE42 | 1U << 1; +constexpr uint32_t cpuid_ecx_XSAVE= 1U << 26; static uint32_t cpuid_ecx() { @@ -382,8 +384,19 @@ static unsigned crc32_avx512(unsigned crc, const char *buf, size_t size, } } -static ATTRIBUTE_NOINLINE int have_vpclmulqdq() +#ifdef __GNUC__ +__attribute__((target("xsave"))) +#endif +static bool os_have_avx512() { + // The following flags must be set: SSE, AVX, OPMASK, ZMM_HI256, HI16_ZMM + return !(~_xgetbv(0 /*_XCR_XFEATURE_ENABLED_MASK*/) & 0xe6); +} + +static ATTRIBUTE_NOINLINE bool have_vpclmulqdq(uint32_t cpuid_ecx) +{ + if (!(cpuid_ecx & cpuid_ecx_XSAVE) || !os_have_avx512()) + return false; # ifdef _MSC_VER int regs[4]; __cpuidex(regs, 7, 0); @@ -410,10 +423,11 @@ static unsigned crc32c_vpclmulqdq(unsigned crc, const void *buf, size_t size) extern "C" my_crc32_t crc32_pclmul_enabled(void) { - if (~cpuid_ecx() & cpuid_ecx_SSE42_AND_PCLMUL) + const uint32_t ecx= cpuid_ecx(); + if (~ecx & cpuid_ecx_SSE42_AND_PCLMUL) return nullptr; #ifdef USE_VPCLMULQDQ - if (have_vpclmulqdq()) + if (have_vpclmulqdq(ecx)) return crc32_vpclmulqdq; #endif return crc32_pclmul; @@ -421,19 +435,20 @@ extern "C" my_crc32_t crc32_pclmul_enabled(void) extern "C" my_crc32_t crc32c_x86_available(void) { + const uint32_t ecx= cpuid_ecx(); #ifdef USE_VPCLMULQDQ - if (have_vpclmulqdq()) + if (have_vpclmulqdq(ecx)) return crc32c_vpclmulqdq; #endif #if SIZEOF_SIZE_T == 8 - switch (cpuid_ecx() & cpuid_ecx_SSE42_AND_PCLMUL) { + switch (ecx & cpuid_ecx_SSE42_AND_PCLMUL) { case cpuid_ecx_SSE42_AND_PCLMUL: return crc32c_3way; case cpuid_ecx_SSE42: return crc32c_sse42; } #else - if (cpuid_ecx() & cpuid_ecx_SSE42) + if (ecx & cpuid_ecx_SSE42) return crc32c_sse42; #endif return nullptr; From 7e5c9ccda55b846328edc44a1e7342c605dcd73d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 29 Jul 2024 15:04:16 +0300 Subject: [PATCH 08/17] MDEV-34502 fixup: Do not cripple MSAN We need to work around deficiencies of Valgrind, and apparently the previous work-around attempts (such as d247d64988fb3b5d348e412813593a13f3be91fa) do not work anymore, definitely not on recent clang-based compilers. MemorySanitizer should be fine; unfortunately we set HAVE_valgrind for it as well. --- storage/innobase/include/mach0data.inl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/innobase/include/mach0data.inl b/storage/innobase/include/mach0data.inl index 94bf4326069..8e95d05c79c 100644 --- a/storage/innobase/include/mach0data.inl +++ b/storage/innobase/include/mach0data.inl @@ -38,7 +38,7 @@ mach_write_to_1( byte* b, /*!< in: pointer to byte where to store */ ulint n) /*!< in: ulint integer to be stored, >= 0, < 256 */ { -#ifndef HAVE_valgrind +#if !defined HAVE_valgrind || __has_feature(memory_sanitizer) ut_ad((n & ~0xFFUL) == 0); #endif @@ -57,7 +57,7 @@ mach_write_to_2( byte* b, /*!< in: pointer to two bytes where to store */ ulint n) /*!< in: ulint integer to be stored */ { -#ifndef HAVE_valgrind +#if !defined HAVE_valgrind || __has_feature(memory_sanitizer) ut_ad((n & ~0xFFFFUL) == 0); #endif From 4bf7c966b362eb9767266f04b04388aa77e22b36 Mon Sep 17 00:00:00 2001 From: Monty Date: Sat, 27 Jul 2024 13:34:26 +0300 Subject: [PATCH 09/17] MDEV-34664: Add an option to fix InnoDB's doubling of secondary index cardinalities (With trivial fixes by sergey@mariadb.com) Added option fix_innodb_cardinality to optimizer_adjust_secondary_key_costs Using fix_innodb_cardinality disables the 'divide by 2' of rec_per_key_int in InnoDB that in effect doubles the Cardinality for secondary keys. This has the biggest effect for indexes where a few rows has the same key value. Using this may also cause table scans for very small tables (which in some cases may be better than an index scan). The user visible effect is that 'SHOW INDEX FROM table_name' will for InnoDB show the true Cardinality (and not 2x the real value). It will also allow the optimizer to chose a better index in some cases as the division by 2 could have a bad effect for tables with 2-5 identical values per key. A few notes about using fix_innodb_cardinality: - It has direct affect for SHOW INDEX FROM table_name. SHOW INDEX will also update the statistics in table share. - The effect of fix_innodb_cardinality for query plans or EXPLAIN is only visible after first open of the table. This is why one must do a flush tables or use SHOW INDEX for the option to take effect. - Using fix_innodb_cardinality can thus affect all user in their query plans if they are using the same tables. Because of this, it is strongly recommended that one uses optimizer_adjust_secondary_key_costs=fix_innodb_cardinality mainly in configuration files to not cause issues for other users. --- mysql-test/main/mysqld--help.result | 7 ++- mysql-test/main/secondary_key_costs.result | 63 +++++++++++++++++++ mysql-test/main/secondary_key_costs.test | 38 +++++++++++ .../sys_vars/r/sysvars_server_embedded.result | 4 +- .../r/sysvars_server_notembedded.result | 4 +- sql/sql_class.cc | 11 ++++ sql/sql_class.h | 1 + sql/sql_priv.h | 1 + sql/sys_vars.cc | 15 +++-- storage/innobase/handler/ha_innodb.cc | 3 +- 10 files changed, 133 insertions(+), 14 deletions(-) diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result index 79c0d7005f2..cabf8037508 100644 --- a/mysql-test/main/mysqld--help.result +++ b/mysql-test/main/mysqld--help.result @@ -719,9 +719,10 @@ The following specify which files/extra groups are read (specified before remain costs. disable_max_seek = Disable 'max_seek optimization' for secondary keys and slight adjustment of filter cost. disable_forced_index_in_group_by = Disable automatic - forced index in GROUP BY. This variable will be deleted - in MariaDB 11.0 as it is not needed with the new 11.0 - optimizer. + forced index in GROUP BY. fix_innodb_cardinality = + Disable doubling of the Cardinality for InnoDB secondary + keys. This variable will be deleted in MariaDB 11.0 as it + is not needed with the new 11.0 optimizer. Use 'ALL' to set all combinations. --optimizer-max-sel-arg-weight=# The maximum weight of the SEL_ARG graph. Set to 0 for no diff --git a/mysql-test/main/secondary_key_costs.result b/mysql-test/main/secondary_key_costs.result index dbdaaa3ed95..b246b666115 100644 --- a/mysql-test/main/secondary_key_costs.result +++ b/mysql-test/main/secondary_key_costs.result @@ -115,3 +115,66 @@ b sum(d) 6 125005000 8 125015000 drop table t1; +# +# MDEV-34664: fix_innodb_cardinality +# +set @save_userstat=@@global.userstat; +set @save_ispsp=@@global.innodb_stats_persistent_sample_pages; +set @@global.innodb_stats_persistent_sample_pages=20; +set @@global.userstat=on; +set use_stat_tables=PREFERABLY_FOR_QUERIES; +create or replace table t1 (a int primary key, b int, c int, d int, key(b,c,d)) engine=innodb; +insert into t1 select seq,seq/100,seq/60,seq/10 from seq_1_to_1000; +create or replace table t2 (a int); +insert into t2 values (1),(2),(3); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +select count(distinct b),count(distinct b,c), count(distinct b,c,d) from t1; +count(distinct b) count(distinct b,c) count(distinct b,c,d) +11 25 125 +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Ignored +t1 0 PRIMARY 1 a A 1000 NULL NULL BTREE NO +t1 1 b 1 b A 22 NULL NULL YES BTREE NO +t1 1 b 2 c A 50 NULL NULL YES BTREE NO +t1 1 b 3 d A 250 NULL NULL YES BTREE NO +explain select * from t1,t2 where t1.b=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where +1 SIMPLE t1 ref b b 5 test.t2.a 45 Using index +set @@optimizer_adjust_secondary_key_costs=8; +explain select * from t1,t2 where t1.b=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where +1 SIMPLE t1 ref b b 5 test.t2.a 45 Using index +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Ignored +t1 0 PRIMARY 1 a A 1000 NULL NULL BTREE NO +t1 1 b 1 b A 11 NULL NULL YES BTREE NO +t1 1 b 2 c A 25 NULL NULL YES BTREE NO +t1 1 b 3 d A 125 NULL NULL YES BTREE NO +flush tables; +explain select * from t1,t2 where t1.b=t2.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where +1 SIMPLE t1 ref b b 5 test.t2.a 90 Using index +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Ignored +t1 0 PRIMARY 1 a A 1000 NULL NULL BTREE NO +t1 1 b 1 b A 11 NULL NULL YES BTREE NO +t1 1 b 2 c A 25 NULL NULL YES BTREE NO +t1 1 b 3 d A 125 NULL NULL YES BTREE NO +connect user2, localhost, root,,; +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Ignored +t1 0 PRIMARY 1 a A 1000 NULL NULL BTREE NO +t1 1 b 1 b A 22 NULL NULL YES BTREE NO +t1 1 b 2 c A 50 NULL NULL YES BTREE NO +t1 1 b 3 d A 250 NULL NULL YES BTREE NO +connection default; +disconnect user2; +drop table t1,t2; +set global userstat=@save_userstat; +set global innodb_stats_persistent_sample_pages=@save_ispsp; +set @@optimizer_adjust_secondary_key_costs=default; diff --git a/mysql-test/main/secondary_key_costs.test b/mysql-test/main/secondary_key_costs.test index bf662d4078d..32e30156a08 100644 --- a/mysql-test/main/secondary_key_costs.test +++ b/mysql-test/main/secondary_key_costs.test @@ -1,6 +1,8 @@ --source include/have_sequence.inc --source include/not_embedded.inc --source include/have_innodb.inc +# Testcase for MDEV-33306 takes ~6 minutes with valgrind: +--source include/not_valgrind.inc # # Show the costs for rowid filter @@ -72,3 +74,39 @@ set @@optimizer_adjust_secondary_key_costs="disable_forced_index_in_group_by"; explain select b, sum(d) from t1 where c=0 group by b; select b, sum(d) from t1 where c=0 group by b; drop table t1; + +--echo # +--echo # MDEV-34664: fix_innodb_cardinality +--echo # + +set @save_userstat=@@global.userstat; +set @save_ispsp=@@global.innodb_stats_persistent_sample_pages; +set @@global.innodb_stats_persistent_sample_pages=20; +set @@global.userstat=on; +set use_stat_tables=PREFERABLY_FOR_QUERIES; + +create or replace table t1 (a int primary key, b int, c int, d int, key(b,c,d)) engine=innodb; +insert into t1 select seq,seq/100,seq/60,seq/10 from seq_1_to_1000; +create or replace table t2 (a int); +insert into t2 values (1),(2),(3); +analyze table t1; +select count(distinct b),count(distinct b,c), count(distinct b,c,d) from t1; +show index from t1; +explain select * from t1,t2 where t1.b=t2.a; +set @@optimizer_adjust_secondary_key_costs=8; +explain select * from t1,t2 where t1.b=t2.a; +show index from t1; +# Flush tables or show index is needed to refresh the data in table share +flush tables; +explain select * from t1,t2 where t1.b=t2.a; +show index from t1; +# Check that the option does not affect other usage +connect (user2, localhost, root,,); +show index from t1; +connection default; +disconnect user2; +drop table t1,t2; +set global userstat=@save_userstat; +set global innodb_stats_persistent_sample_pages=@save_ispsp; + +set @@optimizer_adjust_secondary_key_costs=default; diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index b05f4d494e9..b5c47ac5ecd 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -2275,11 +2275,11 @@ COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME OPTIMIZER_ADJUST_SECONDARY_KEY_COSTS VARIABLE_SCOPE SESSION VARIABLE_TYPE SET -VARIABLE_COMMENT A bit field with the following values: adjust_secondary_key_cost = Update secondary key costs for ranges to be at least 5x of clustered primary key costs. disable_max_seek = Disable 'max_seek optimization' for secondary keys and slight adjustment of filter cost. disable_forced_index_in_group_by = Disable automatic forced index in GROUP BY. This variable will be deleted in MariaDB 11.0 as it is not needed with the new 11.0 optimizer. +VARIABLE_COMMENT A bit field with the following values: adjust_secondary_key_cost = Update secondary key costs for ranges to be at least 5x of clustered primary key costs. disable_max_seek = Disable 'max_seek optimization' for secondary keys and slight adjustment of filter cost. disable_forced_index_in_group_by = Disable automatic forced index in GROUP BY. fix_innodb_cardinality = Disable doubling of the Cardinality for InnoDB secondary keys. This variable will be deleted in MariaDB 11.0 as it is not needed with the new 11.0 optimizer. NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST adjust_secondary_key_cost,disable_max_seek,disable_forced_index_in_group_by +ENUM_VALUE_LIST adjust_secondary_key_cost,disable_max_seek,disable_forced_index_in_group_by,fix_innodb_cardinality READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME OPTIMIZER_MAX_SEL_ARGS diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 9c9384f9533..59b9cbb8d96 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -2435,11 +2435,11 @@ COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME OPTIMIZER_ADJUST_SECONDARY_KEY_COSTS VARIABLE_SCOPE SESSION VARIABLE_TYPE SET -VARIABLE_COMMENT A bit field with the following values: adjust_secondary_key_cost = Update secondary key costs for ranges to be at least 5x of clustered primary key costs. disable_max_seek = Disable 'max_seek optimization' for secondary keys and slight adjustment of filter cost. disable_forced_index_in_group_by = Disable automatic forced index in GROUP BY. This variable will be deleted in MariaDB 11.0 as it is not needed with the new 11.0 optimizer. +VARIABLE_COMMENT A bit field with the following values: adjust_secondary_key_cost = Update secondary key costs for ranges to be at least 5x of clustered primary key costs. disable_max_seek = Disable 'max_seek optimization' for secondary keys and slight adjustment of filter cost. disable_forced_index_in_group_by = Disable automatic forced index in GROUP BY. fix_innodb_cardinality = Disable doubling of the Cardinality for InnoDB secondary keys. This variable will be deleted in MariaDB 11.0 as it is not needed with the new 11.0 optimizer. NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST adjust_secondary_key_cost,disable_max_seek,disable_forced_index_in_group_by +ENUM_VALUE_LIST adjust_secondary_key_cost,disable_max_seek,disable_forced_index_in_group_by,fix_innodb_cardinality READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME OPTIMIZER_MAX_SEL_ARGS diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 6419a58fbe4..539ab77db63 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -5374,6 +5374,17 @@ extern "C" int thd_current_status(MYSQL_THD thd) } +extern "C" int thd_double_innodb_cardinality(MYSQL_THD thd) +{ + /* + The original behavior was to double the cardinality. + OPTIMIZER_FIX_INNODB_CARDINALITY means do not double. + */ + return !(thd->variables.optimizer_adjust_secondary_key_costs & + OPTIMIZER_FIX_INNODB_CARDINALITY); +} + + extern "C" enum enum_server_command thd_current_command(MYSQL_THD thd) { return thd->get_command(); diff --git a/sql/sql_class.h b/sql/sql_class.h index a9d89871025..a347700f72f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -214,6 +214,7 @@ extern "C" const char *thd_client_ip(MYSQL_THD thd); extern "C" LEX_CSTRING *thd_current_db(MYSQL_THD thd); extern "C" int thd_current_status(MYSQL_THD thd); extern "C" enum enum_server_command thd_current_command(MYSQL_THD thd); +extern "C" int thd_double_innodb_cardinality(MYSQL_THD thd); /** @class CSET_STRING diff --git a/sql/sql_priv.h b/sql/sql_priv.h index 7a7a0241ab0..0bcb09a80ad 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -274,6 +274,7 @@ #define OPTIMIZER_ADJ_SEC_KEY_COST (1) #define OPTIMIZER_ADJ_DISABLE_MAX_SEEKS (2) #define OPTIMIZER_ADJ_DISABLE_FORCE_INDEX_GROUP_BY (4) +#define OPTIMIZER_FIX_INNODB_CARDINALITY (8) /* Replication uses 8 bytes to store SQL_MODE in the binary log. The day you diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 86c1b50e9af..42ec52b38a9 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2823,18 +2823,21 @@ static Sys_var_ulong Sys_optimizer_trace_max_mem_size( */ static const char *adjust_secondary_key_cost[]= { - "adjust_secondary_key_cost", "disable_max_seek", "disable_forced_index_in_group_by", 0 + "adjust_secondary_key_cost", "disable_max_seek", "disable_forced_index_in_group_by", "fix_innodb_cardinality",0 }; static Sys_var_set Sys_optimizer_adjust_secondary_key_costs( "optimizer_adjust_secondary_key_costs", "A bit field with the following values: " - "adjust_secondary_key_cost = Update secondary key costs for ranges to be at least " - "5x of clustered primary key costs. " - "disable_max_seek = Disable 'max_seek optimization' for secondary keys and slight " - "adjustment of filter cost. " - "disable_forced_index_in_group_by = Disable automatic forced index in GROUP BY. " + "adjust_secondary_key_cost = Update secondary key costs for ranges to be " + "at least 5x of clustered primary key costs. " + "disable_max_seek = Disable 'max_seek optimization' for secondary keys and " + "slight adjustment of filter cost. " + "disable_forced_index_in_group_by = Disable automatic forced index in " + "GROUP BY. " + "fix_innodb_cardinality = Disable doubling of the Cardinality for InnoDB " + "secondary keys. " "This variable will be deleted in MariaDB 11.0 as it is not needed with the " "new 11.0 optimizer.", SESSION_VAR(optimizer_adjust_secondary_key_costs), CMD_LINE(REQUIRED_ARG), diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 790274f46b3..b99d5873bf5 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -15013,7 +15013,8 @@ ha_innobase::info_low( index selectivity is 2 times better than our estimate: */ - rec_per_key_int = rec_per_key_int / 2; + rec_per_key_int /= 1 + + thd_double_innodb_cardinality(m_user_thd); if (rec_per_key_int == 0) { rec_per_key_int = 1; From 48b256a7e283a84802d94060b77bce1e0eab81a0 Mon Sep 17 00:00:00 2001 From: Rex Date: Tue, 2 Jul 2024 12:27:41 +1100 Subject: [PATCH 10/17] MDEV-34506 2nd execution name resolution problem with pushdown into unions Statements affected by this bug need all the following to be true 1) a derived table table or view whose specification contains a set operation at the top level. 2) a grouping operator (group by/having) operating on a column alias other than in the first select of the union/intersect 3) an outer condition that will be pushed into all selects in this union/intersect, either into the where or having clause When pushing a condition into all selects of a unit with more than one select, pushdown_cond_for_derived() renames items so we can re-use the condition being pushed. These names need to be saved and reset for correct name resolution on second execution of prepared statements. Reviewed by Igor Babaev (igor@mariadb.com) --- mysql-test/main/derived_cond_pushdown.result | 495 +++++++++++++++++++ mysql-test/main/derived_cond_pushdown.test | 87 ++++ sql/sql_derived.cc | 1 + 3 files changed, 583 insertions(+) diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result index f13f04a26dc..4fa8867e2f4 100644 --- a/mysql-test/main/derived_cond_pushdown.result +++ b/mysql-test/main/derived_cond_pushdown.result @@ -18557,3 +18557,498 @@ valdouble valint1 5 3289988 DROP TABLE t1,t2; # End of 10.4 tests +# MDEV-34506 2nd execution name resolution problem with pushdown into +# unions +# +# Statements affected by this bug need all the following to be true +# 1) a derived table table or view whose specification contains a set +# operation at the top level. +# 2) a grouping operator (group by/having) operating on a column alias +# other than in the first select of the union/intersect +# 3) an outer condition that will be pushed into all selects in this +# union/intersect, either into the where or having clause +# +# When pushing a condition into all selects of a unit with more than one +# select, pushdown_cond_for_derived() renames items so we can re-use the +# condition being pushed. +# These names need to be saved and reset for correct name resolution on +# second execution of prepared statements. +create table t1 (c1 int, c2 int, c3 int); +insert into t1 values (1,2,3),(1,2,2),(4,5,6); +insert into t1 values (17,8,9),(11,11,12); +create table t2 (c4 int, c5 int, c6 int); +insert into t2 values (7,8,9),(10,11,12); +prepare stmt from 'select * from +( +select c1, sum(c3) as s from t1 group by c1 +union +select c4 as c, sum(c6) as u from t2 group by c +) dt +where c1 > 6'; +execute stmt; +c1 s +11 12 +17 9 +7 9 +10 12 +execute stmt; +c1 s +11 12 +17 9 +7 9 +10 12 +prepare stmt from 'explain format=json select * from +( +select c1, sum(c3) as s from t1 group by c1 +union +select c4 as c, sum(c6) as u from t2 group by c +) dt +where c1 > 6'; +execute stmt; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 7, + "filtered": 100, + "attached_condition": "dt.c1 > 6", + "materialized": { + "query_block": { + "union_result": { + "table_name": "", + "access_type": "ALL", + "query_specifications": [ + { + "query_block": { + "select_id": 2, + "filesort": { + "sort_key": "t1.c1", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.c1 > 6" + } + } + } + } + }, + { + "query_block": { + "select_id": 3, + "operation": "UNION", + "filesort": { + "sort_key": "t2.c4", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 2, + "filtered": 100, + "attached_condition": "t2.c4 > 6" + } + } + } + } + } + ] + } + } + } + } + } +} +execute stmt; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 7, + "filtered": 100, + "attached_condition": "dt.c1 > 6", + "materialized": { + "query_block": { + "union_result": { + "table_name": "", + "access_type": "ALL", + "query_specifications": [ + { + "query_block": { + "select_id": 2, + "filesort": { + "sort_key": "t1.c1", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.c1 > 6" + } + } + } + } + }, + { + "query_block": { + "select_id": 3, + "operation": "UNION", + "filesort": { + "sort_key": "t2.c4", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 2, + "filtered": 100, + "attached_condition": "t2.c4 > 6" + } + } + } + } + } + ] + } + } + } + } + } +} +prepare stmt from 'select * from +( +select c1, c2, sum(c3) as s from t1 group by c1, c2 having s > 2 +union +select c4, c5, sum(c6) as u from t2 group by c4, c5 having u > 3 +) dt +where c2 > 5'; +execute stmt; +c1 c2 s +11 11 12 +17 8 9 +7 8 9 +10 11 12 +execute stmt; +c1 c2 s +11 11 12 +17 8 9 +7 8 9 +10 11 12 +prepare stmt from 'explain format=json select * from +( +select c1, c2, sum(c3) as s from t1 group by c1, c2 having s > 2 +union +select c4, c5, sum(c6) as u from t2 group by c4, c5 having u > 3 +) dt +where c2 > 5'; +execute stmt; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 7, + "filtered": 100, + "attached_condition": "dt.c2 > 5", + "materialized": { + "query_block": { + "union_result": { + "table_name": "", + "access_type": "ALL", + "query_specifications": [ + { + "query_block": { + "select_id": 2, + "having_condition": "s > 2", + "filesort": { + "sort_key": "t1.c1, t1.c2", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.c2 > 5" + } + } + } + } + }, + { + "query_block": { + "select_id": 3, + "operation": "UNION", + "having_condition": "s > 3", + "filesort": { + "sort_key": "t2.c4, t2.c5", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 2, + "filtered": 100, + "attached_condition": "t2.c5 > 5" + } + } + } + } + } + ] + } + } + } + } + } +} +execute stmt; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 7, + "filtered": 100, + "attached_condition": "dt.c2 > 5", + "materialized": { + "query_block": { + "union_result": { + "table_name": "", + "access_type": "ALL", + "query_specifications": [ + { + "query_block": { + "select_id": 2, + "having_condition": "s > 2", + "filesort": { + "sort_key": "t1.c1, t1.c2", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.c2 > 5" + } + } + } + } + }, + { + "query_block": { + "select_id": 3, + "operation": "UNION", + "having_condition": "s > 3", + "filesort": { + "sort_key": "t2.c4, t2.c5", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 2, + "filtered": 100, + "attached_condition": "t2.c5 > 5" + } + } + } + } + } + ] + } + } + } + } + } +} +prepare stmt from 'select * +from +( +select c1, c2, max(c3) as max_c, avg(c3) as avg_c +from t1 +group by c1,c2 +having max_c < 7 +union +select c4, c5, max(c6) as u, avg(c6) as w +from t2 +group by c4, c5 +having u < 10 +) dt, +t2 +where dt.max_c > 6 and t2.c6 > dt.c1'; +execute stmt; +c1 c2 max_c avg_c c4 c5 c6 +7 8 9 9.0000 7 8 9 +7 8 9 9.0000 10 11 12 +execute stmt; +c1 c2 max_c avg_c c4 c5 c6 +7 8 9 9.0000 7 8 9 +7 8 9 9.0000 10 11 12 +prepare stmt from 'explain format=json select * +from +( +select c1, c2, max(c3) as max_c, avg(c3) as avg_c +from t1 +group by c1,c2 +having max_c < 7 +union +select c4, c5, max(c6) as u, avg(c6) as w +from t2 +group by c4, c5 +having u < 10 +) dt, +t2 +where dt.max_c > 6 and t2.c6 > dt.c1'; +execute stmt; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 2, + "filtered": 100 + }, + "block-nl-join": { + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 7, + "filtered": 100, + "attached_condition": "dt.max_c > 6" + }, + "buffer_type": "flat", + "buffer_size": "173", + "join_type": "BNL", + "attached_condition": "t2.c6 > dt.c1", + "materialized": { + "query_block": { + "union_result": { + "table_name": "", + "access_type": "ALL", + "query_specifications": [ + { + "query_block": { + "select_id": 2, + "having_condition": "max_c < 7 and max_c > 6", + "filesort": { + "sort_key": "t1.c1, t1.c2", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100 + } + } + } + } + }, + { + "query_block": { + "select_id": 3, + "operation": "UNION", + "having_condition": "max_c < 10 and max_c > 6", + "filesort": { + "sort_key": "t2.c4, t2.c5", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 2, + "filtered": 100 + } + } + } + } + } + ] + } + } + } + } + } +} +execute stmt; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 2, + "filtered": 100 + }, + "block-nl-join": { + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 7, + "filtered": 100, + "attached_condition": "dt.max_c > 6" + }, + "buffer_type": "flat", + "buffer_size": "173", + "join_type": "BNL", + "attached_condition": "t2.c6 > dt.c1", + "materialized": { + "query_block": { + "union_result": { + "table_name": "", + "access_type": "ALL", + "query_specifications": [ + { + "query_block": { + "select_id": 2, + "having_condition": "max_c < 7 and max_c > 6", + "filesort": { + "sort_key": "t1.c1, t1.c2", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100 + } + } + } + } + }, + { + "query_block": { + "select_id": 3, + "operation": "UNION", + "having_condition": "max_c < 10 and max_c > 6", + "filesort": { + "sort_key": "t2.c4, t2.c5", + "temporary_table": { + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 2, + "filtered": 100 + } + } + } + } + } + ] + } + } + } + } + } +} +drop table t1, t2; +# End of 10.5 tests diff --git a/mysql-test/main/derived_cond_pushdown.test b/mysql-test/main/derived_cond_pushdown.test index ce303779a41..179e033889f 100644 --- a/mysql-test/main/derived_cond_pushdown.test +++ b/mysql-test/main/derived_cond_pushdown.test @@ -4102,3 +4102,90 @@ eval $q; DROP TABLE t1,t2; --echo # End of 10.4 tests + +--echo # MDEV-34506 2nd execution name resolution problem with pushdown into +--echo # unions +--echo # +--echo # Statements affected by this bug need all the following to be true +--echo # 1) a derived table table or view whose specification contains a set +--echo # operation at the top level. +--echo # 2) a grouping operator (group by/having) operating on a column alias +--echo # other than in the first select of the union/intersect +--echo # 3) an outer condition that will be pushed into all selects in this +--echo # union/intersect, either into the where or having clause +--echo # +--echo # When pushing a condition into all selects of a unit with more than one +--echo # select, pushdown_cond_for_derived() renames items so we can re-use the +--echo # condition being pushed. +--echo # These names need to be saved and reset for correct name resolution on +--echo # second execution of prepared statements. + +create table t1 (c1 int, c2 int, c3 int); +insert into t1 values (1,2,3),(1,2,2),(4,5,6); +insert into t1 values (17,8,9),(11,11,12); +create table t2 (c4 int, c5 int, c6 int); +insert into t2 values (7,8,9),(10,11,12); +let $q=select * from + ( + select c1, sum(c3) as s from t1 group by c1 + union + select c4 as c, sum(c6) as u from t2 group by c + ) dt + where c1 > 6; +eval prepare stmt from '$q'; +execute stmt; +execute stmt; + +eval prepare stmt from 'explain format=json $q'; +--source include/analyze-format.inc +execute stmt; +--source include/analyze-format.inc +execute stmt; + +let $q=select * from + ( + select c1, c2, sum(c3) as s from t1 group by c1, c2 having s > 2 + union + select c4, c5, sum(c6) as u from t2 group by c4, c5 having u > 3 + ) dt + where c2 > 5; + +eval prepare stmt from '$q'; +execute stmt; +execute stmt; + +eval prepare stmt from 'explain format=json $q'; +--source include/analyze-format.inc +execute stmt; +--source include/analyze-format.inc +execute stmt; + +let $q=select * + from + ( + select c1, c2, max(c3) as max_c, avg(c3) as avg_c + from t1 + group by c1,c2 + having max_c < 7 + union + select c4, c5, max(c6) as u, avg(c6) as w + from t2 + group by c4, c5 + having u < 10 + ) dt, + t2 + where dt.max_c > 6 and t2.c6 > dt.c1; + +eval prepare stmt from '$q'; +execute stmt; +execute stmt; + +eval prepare stmt from 'explain format=json $q'; +--source include/analyze-format.inc +execute stmt; +--source include/analyze-format.inc +execute stmt; + +drop table t1, t2; + +--echo # End of 10.5 tests diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index a721875051b..bd55c533108 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -1557,6 +1557,7 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) if (sl != first_sl) { DBUG_ASSERT(sl->item_list.elements == first_sl->item_list.elements); + sl->save_item_list_names(thd); List_iterator_fast it(sl->item_list); List_iterator_fast nm_it(unit->types); while (Item *item= it++) From c038b3c05ed90041333dc869e3435c301210a3c4 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 30 Jul 2024 12:05:38 +0530 Subject: [PATCH 11/17] MDEV-34181 Instant table aborts after discard tablespace - commit 85db5347311340e39753b0200fb9d459a5024535 (MDEV-33400) retains the instantness in the table definition after discard tablespace. So there is no need to assign n_core_null_bytes during instant table preparation unless they are not initialized. --- mysql-test/suite/innodb/r/import_bugs.result | 26 ++++++++++++++++++++ mysql-test/suite/innodb/t/import_bugs.test | 20 +++++++++++++++ storage/innobase/handler/handler0alter.cc | 10 +++++--- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/innodb/r/import_bugs.result b/mysql-test/suite/innodb/r/import_bugs.result index 82942e85301..f62c3ee4279 100644 --- a/mysql-test/suite/innodb/r/import_bugs.result +++ b/mysql-test/suite/innodb/r/import_bugs.result @@ -61,4 +61,30 @@ id 4 5 DROP TABLE t2; +# +# MDEV-34181 Instant table aborts after discard tablespace +# +CREATE TABLE t1(c3 INT, c2 INT, c1 INT KEY)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, 1, 1), (2, 2, 2); +CREATE TABLE t2 (c1 INT KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES(1); +ALTER TABLE t2 ADD c2 INT; +FLUSH TABLES t1 FOR EXPORT; +UNLOCK TABLES; +ALTER TABLE t2 DISCARD TABLESPACE; +ALTER TABLE t2 ADD c3 INT FIRST; +Warnings: +Warning 1814 Tablespace has been discarded for table `t2` +ALTER TABLE t2 IMPORT TABLESPACE; +Warnings: +Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t2.cfg', will attempt to import without schema verification +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `c3` int(11) DEFAULT NULL, + `c1` int(11) NOT NULL, + `c2` int(11) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +DROP TABLE t2, t1; # End of 10.5 tests diff --git a/mysql-test/suite/innodb/t/import_bugs.test b/mysql-test/suite/innodb/t/import_bugs.test index d9c5b6b1d89..5c9fdc602fd 100644 --- a/mysql-test/suite/innodb/t/import_bugs.test +++ b/mysql-test/suite/innodb/t/import_bugs.test @@ -78,4 +78,24 @@ INSERT INTO t2() VALUES(); SELECT * FROM t2 ORDER BY id; DROP TABLE t2; +--echo # +--echo # MDEV-34181 Instant table aborts after discard tablespace +--echo # +CREATE TABLE t1(c3 INT, c2 INT, c1 INT KEY)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, 1, 1), (2, 2, 2); +CREATE TABLE t2 (c1 INT KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES(1); +ALTER TABLE t2 ADD c2 INT; +FLUSH TABLES t1 FOR EXPORT; +let $datadir=`select @@datadir`; +--copy_file $datadir/test/t1.ibd $datadir/test/imp_t1.ibd +UNLOCK TABLES; +ALTER TABLE t2 DISCARD TABLESPACE; +ALTER TABLE t2 ADD c3 INT FIRST; +--copy_file $datadir/test/imp_t1.ibd $datadir/test/t2.ibd + +--replace_regex /opening '.*\/test\//opening '.\/test\// +ALTER TABLE t2 IMPORT TABLESPACE; +SHOW CREATE TABLE t2; +DROP TABLE t2, t1; --echo # End of 10.5 tests diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 79024177125..b5a76bfcdc2 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -374,10 +374,12 @@ found_j: } } - /* In case of discarded tablespace, InnoDB can't - read the root page. So assign the null bytes based - on nullabled fields */ - if (!oindex.table->space) { + /* Discard tablespace doesn't remove the instantness + from the table definition. if n_core_null_bytes wasn't + initialized then assign it based on nullable fields */ + if (!oindex.table->space + && oindex.n_core_null_bytes + == dict_index_t::NO_CORE_NULL_BYTES) { oindex.n_core_null_bytes = static_cast( UT_BITS_IN_BYTES(unsigned(oindex.n_nullable))); } From ee5f7692d78061a938f7a9a3f2d84c0875b8795f Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 23 Jul 2024 17:37:34 +0530 Subject: [PATCH 12/17] MDEV-34357 InnoDB: Assertion failure in file ./storage/innobase/page/page0zip.cc line 4211 During InnoDB root page split, InnoDB does the following 1) First move the root records to the new page(p1) 2) Empty the root, insert the node pointer to the root page 3) Split the new page and make it as child nodes. 4) Finds the split record, allocate another new page(p2) to the index 5) InnoDB stores the record(ret) predecessor to the supremum record of the page (p2). 6) In page_copy_rec_list_start(), move the records from p1 to p2 upto the split record 6) Given table is a compressed row format page, InnoDB attempts to compress the page p2 and failed (due to innodb_compression_level = 0) 7) Since the compression fails, InnoDB gets the number of preceding records(ret_pos) of a record (ret) on the page (p2) 8) Page (p2) is a new page, ret points to infimum record. ret_pos can be 0. InnoDB have wrong condition that ret_pos shouldn't be 0 and returns corruption. InnoDB has similar wrong check in page_copy_rec_list_end() --- storage/innobase/page/page0page.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc index 21b291e3a8b..d3680ce51ba 100644 --- a/storage/innobase/page/page0page.cc +++ b/storage/innobase/page/page0page.cc @@ -811,11 +811,11 @@ zip_reorganize: the predefined infimum record, then it would still be the infimum, and we would have ret_pos == 0. */ - if (UNIV_UNLIKELY(!ret_pos - || ret_pos == ULINT_UNDEFINED)) { + if (UNIV_UNLIKELY(ret_pos == ULINT_UNDEFINED)) { *err = DB_CORRUPTION; return nullptr; } + *err = page_zip_reorganize(new_block, index, page_zip_level, mtr); switch (*err) { From fdda8171b2391f94905a07e8072d0b5f2e44ae74 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 30 Jul 2024 17:49:09 +0300 Subject: [PATCH 13/17] MDEV-34580: Assertion `(key_part->key_part_flag & 4) == 0' failed key_hashnr Remove an assert added by fix for MDEV-34417. BNL-H join can be used with prefix keys. This happens when there are real prefix indexes on the equi-join columns (although it probably doesn't make a lot of sense). Anyway, remove the assert. The code receives properly truncated key values for hashing/comparison so it can handle them just fine. --- mysql-test/main/join_cache.result | 20 ++++++++++++++++++++ mysql-test/main/join_cache.test | 22 ++++++++++++++++++++++ sql/key.cc | 14 ++++++++------ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/mysql-test/main/join_cache.result b/mysql-test/main/join_cache.result index 1e42f798d2c..3546d74aaeb 100644 --- a/mysql-test/main/join_cache.result +++ b/mysql-test/main/join_cache.result @@ -6420,3 +6420,23 @@ DROP TABLE t1,t2,t3; # # End of 10.4 tests # +# +# MDEV-34580: Assertion `(key_part->key_part_flag & 4) == 0' failed key_hashnr +# +SET join_cache_level=3; +CREATE TABLE t1 ( a TIMESTAMP , b varchar(100), c varchar(10) ) ; +INSERT INTO t1 (b,c) VALUES ('GHOBS','EMLCG'),('t','p'); +CREATE TABLE t2 (a varchar(100), b varchar(100), c varchar(10) , KEY b (b(66))) ; +insert into t2 select seq, seq, seq from seq_1_to_20; +explain +SELECT t1.a FROM t1 JOIN t2 ON t1.b = t2.b ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +1 SIMPLE t2 hash_ALL b #hash#b 69 test.t1.b 20 Using where; Using join buffer (flat, BNLH join) +SELECT t1.a FROM t1 JOIN t2 ON t1.b = t2.b ; +a +set join_cache_level=default; +DROP TABLE t1, t2; +# +# End of 10.5 tests +# diff --git a/mysql-test/main/join_cache.test b/mysql-test/main/join_cache.test index e9c81a08562..0614e2a1ba3 100644 --- a/mysql-test/main/join_cache.test +++ b/mysql-test/main/join_cache.test @@ -4300,3 +4300,25 @@ DROP TABLE t1,t2,t3; --echo # --echo # End of 10.4 tests --echo # + +--echo # +--echo # MDEV-34580: Assertion `(key_part->key_part_flag & 4) == 0' failed key_hashnr +--echo # +--source include/have_sequence.inc +SET join_cache_level=3; + +CREATE TABLE t1 ( a TIMESTAMP , b varchar(100), c varchar(10) ) ; +INSERT INTO t1 (b,c) VALUES ('GHOBS','EMLCG'),('t','p'); + +CREATE TABLE t2 (a varchar(100), b varchar(100), c varchar(10) , KEY b (b(66))) ; +insert into t2 select seq, seq, seq from seq_1_to_20; + +explain +SELECT t1.a FROM t1 JOIN t2 ON t1.b = t2.b ; +SELECT t1.a FROM t1 JOIN t2 ON t1.b = t2.b ; + +set join_cache_level=default; +DROP TABLE t1, t2; +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/sql/key.cc b/sql/key.cc index 58b2cfbb47a..fa0239b49fc 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -755,10 +755,12 @@ ulong key_hashnr(KEY *key_info, uint used_key_parts, const uchar *key) if (is_string) { /* - Prefix keys are not possible in BNLH joins. - Use the whole string to calculate the hash. + Surprisingly, BNL-H joins may use prefix keys. This may happen + when there is a real index on the column used in equi-join. + + In this case, the passed key tuple is already a prefix, no + special handling is required. */ - DBUG_ASSERT((key_part->key_part_flag & HA_PART_KEY_SEG) == 0); cs->hash_sort(pos+pack_length, length, &nr, &nr2); key+= pack_length; } @@ -862,10 +864,10 @@ bool key_buf_cmp(KEY *key_info, uint used_key_parts, if (is_string) { /* - Prefix keys are not possible in BNLH joins. - Compare whole strings. + Surprisingly, BNL-H joins may use prefix keys. This may happen + when there is a real index on the column used in equi-join. + In this case, we get properly truncated prefixes here. */ - DBUG_ASSERT((key_part->key_part_flag & HA_PART_KEY_SEG) == 0); if (cs->strnncollsp(pos1 + pack_length, length1, pos2 + pack_length, length2)) return true; From 811614d412427ab7eaffd8cd5144a3d802b46f8e Mon Sep 17 00:00:00 2001 From: Hugo Wen Date: Fri, 19 Jul 2024 22:57:51 +0000 Subject: [PATCH 14/17] MDEV-34625 Fix undefined behavior of using uninitialized member variables Commit a8a75ba2d causes the MariaDB server to crash, usually with signal 11, at random code locations due to invalid pointer values during any table operation. This issue occurs when the server is built with -O3 and other customized compiler flags. For example, the command `use db1;` causes server to crash in the `check_table_access` function at line sql_parse.cc:7080 because `tables->correspondent_table` is an invalid pointer value of 0x1. The crashes are due to undefined behavior from using uninitialized variables. The problematic commit a8a75ba2d introduces code that allocates memory and sets it to 0 using thd->calloc before initializing it with a placement new operation. This process depends on setting memory to 0 to initialize member variables not explicitly set in the constructor. However, the compiler can optimize out the memset/bfill, leading to uninitialized values and unpredictable issues. Once a constructor function initializes an object, any uninitialized variables within that object are subject to undefined behavior. The state of memory before the constructor runs, whether it involves memset or was used for other purposes, is irrelevant after the placement new operation. This behavior can be demonstrated with this [test](https://gcc.godbolt.org/z/5n87z1raG) I wrote to examine the assembly code. The code in MariaDB can be abstracted to the following, though it has many layers wrapped around it and more complex logic, causing slight differences in optimization in the MariaDB build. To summarize, on x86, the memset in the following code is optimized out with both -O2 and -O3 in GCC 13, and is only preserved in the much older GCC 4.9. struct S { int i; // uninitialized in consturctor S() {}; }; int bar() { void *buf = malloc(sizeof(S)); memset(buf, 0, sizeof(S)); // optimized out S* s = new(buf) S; return s->i; } With GCC13 -O3: bar(): sub rsp, 8 mov edi, 4 call malloc mov eax, DWORD PTR [rax] add rsp, 8 ret With GCC4.9 -O3 bar(): sub rsp, 8 mov edi, 4 call malloc mov DWORD PTR [rax], 0 xor eax, eax add rsp, 8 ret Now we ensure the constructor initializes variables correctly by running the reset() function in the constructor to perform the memset/bfill(0) operation. After applying the fix, the crash is gone. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services. --- sql/sql_parse.cc | 2 +- sql/table.cc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 77adc6db59a..ea7b8325af2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -8375,7 +8375,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, } bool has_alias_ptr= alias != nullptr; - void *memregion= thd->calloc(sizeof(TABLE_LIST)); + void *memregion= thd->alloc(sizeof(TABLE_LIST)); TABLE_LIST *ptr= new (memregion) TABLE_LIST(thd, db, fqtn, alias_str, has_alias_ptr, table, lock_type, mdl_type, table_options, diff --git a/sql/table.cc b/sql/table.cc index 1906acd14e2..373c70c5983 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5865,6 +5865,7 @@ TABLE_LIST::TABLE_LIST(THD *thd, List *index_hints_ptr, LEX_STRING *option_ptr) { + reset(); db= db_str; is_fqtn= fqtn; alias= alias_str; From 533e6d5d13921948bf451b6a9c3628d4c1699383 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 30 Jul 2024 23:59:00 +0530 Subject: [PATCH 15/17] MDEV-34670 IMPORT TABLESPACE unnecessary traverses tablespace list Problem: ======== - After the commit ada1074bb10359342ee00e220fe9c172574265fb (MDEV-14398) fil_crypt_set_encrypt_tables() iterates through all tablespaces to fill the default_encrypt tables list. This was a trigger to encrypt or decrypt when key rotation age is set to 0. But import tablespace does call fil_crypt_set_encrypt_tables() unnecessarily. The motivation for the call is to signal the encryption threads. Fix: ==== ha_innobase::discard_or_import_tablespace: Remove the fil_crypt_set_encrypt_tables() and add the import tablespace to the default encrypt list if necessary --- .../r/innodb_encryption_discard_import.result | 41 ++++++++++++++ .../t/innodb_encryption_discard_import.test | 56 ++++++++++++++++++- storage/innobase/fil/fil0crypt.cc | 20 +++++++ storage/innobase/handler/ha_innodb.cc | 2 +- storage/innobase/include/fil0crypt.h | 5 ++ 5 files changed, 122 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/encryption/r/innodb_encryption_discard_import.result b/mysql-test/suite/encryption/r/innodb_encryption_discard_import.result index 18082027660..95797da2e15 100644 --- a/mysql-test/suite/encryption/r/innodb_encryption_discard_import.result +++ b/mysql-test/suite/encryption/r/innodb_encryption_discard_import.result @@ -1,3 +1,5 @@ +SET @start_encr_threads = @@global.innodb_encryption_threads; +SET @start_encrypt_tables = @@global.innodb_encrypt_tables; CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB encrypted=yes; CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB; CREATE TABLE t3 (id INT NOT NULL PRIMARY KEY, a VARCHAR(255)) ENGINE=InnoDB row_format=compressed encrypted=yes; @@ -116,3 +118,42 @@ NOT FOUND /temp/ in t2.ibd # t3 ... on expecting NOT FOUND UNLOCK TABLES; DROP TABLE t1, t2, t3; +# +# MDEV-34670 IMPORT TABLESPACE unnecessary traverses +# tablespace list +# +SET GLOBAL innodb_encrypt_tables= OFF; +SET GLOBAL innodb_encryption_threads= 0; +CREATE TABLE t1(f1 int,f2 text)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, "InnoDB"); +CREATE TABLE t2 LIKE t1; +ALTER TABLE t2 DISCARD TABLESPACE; +FLUSH TABLES t1 FOR EXPORT; +UNLOCK TABLES; +ALTER TABLE t2 IMPORT TABLESPACE; +SET GLOBAL innodb_encryption_threads=2; +SET GLOBAL innodb_encrypt_tables = ON; +# Wait max 10 min for key encryption threads to encrypt all spaces +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; +NAME +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; +NAME +innodb_system +test/t1 +test/t2 +SET GLOBAL innodb_encrypt_tables = OFF; +# Wait max 10 min for key encryption threads to decrypt all spaces +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; +NAME +innodb_system +test/t1 +test/t2 +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; +NAME +DROP TABLE t1, t2; +SET GLOBAL innodb_encryption_threads=@start_encr_threads; +SET GLOBAL innodb_encrypt_tables=@start_encrypt_tables; diff --git a/mysql-test/suite/encryption/t/innodb_encryption_discard_import.test b/mysql-test/suite/encryption/t/innodb_encryption_discard_import.test index 5f02d966e7e..e33aaec3e21 100644 --- a/mysql-test/suite/encryption/t/innodb_encryption_discard_import.test +++ b/mysql-test/suite/encryption/t/innodb_encryption_discard_import.test @@ -2,7 +2,8 @@ -- source include/have_example_key_management_plugin.inc -- source include/not_valgrind.inc -- source include/not_embedded.inc - +SET @start_encr_threads = @@global.innodb_encryption_threads; +SET @start_encrypt_tables = @@global.innodb_encrypt_tables; let MYSQLD_DATADIR = `SELECT @@datadir`; --let SEARCH_RANGE = 10000000 @@ -124,3 +125,56 @@ FLUSH TABLES t1, t2, t3 FOR EXPORT; UNLOCK TABLES; DROP TABLE t1, t2, t3; + +--echo # +--echo # MDEV-34670 IMPORT TABLESPACE unnecessary traverses +--echo # tablespace list +--echo # +SET GLOBAL innodb_encrypt_tables= OFF; +SET GLOBAL innodb_encryption_threads= 0; + +CREATE TABLE t1(f1 int,f2 text)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1, "InnoDB"); +CREATE TABLE t2 LIKE t1; +ALTER TABLE t2 DISCARD TABLESPACE; +FLUSH TABLES t1 FOR EXPORT; +--copy_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_DATADIR/test/t2.cfg +--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd +UNLOCK TABLES; +ALTER TABLE t2 IMPORT TABLESPACE; + +SET GLOBAL innodb_encryption_threads=2; +SET GLOBAL innodb_encrypt_tables = ON; + +--let $tables_count= `select count(*) + @@global.innodb_undo_tablespaces + 1 from information_schema.tables where engine = 'InnoDB'` + +--echo # Wait max 10 min for key encryption threads to encrypt all spaces +--let $wait_timeout= 600 +--let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +--source include/wait_condition.inc + +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; + +SET GLOBAL innodb_encrypt_tables = OFF; + +--echo # Wait max 10 min for key encryption threads to decrypt all spaces +--let $wait_timeout= 600 +--let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +--source include/wait_condition.inc + +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; + +--sorted_result +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 +AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; + +DROP TABLE t1, t2; +SET GLOBAL innodb_encryption_threads=@start_encr_threads; +SET GLOBAL innodb_encrypt_tables=@start_encrypt_tables; diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 3cccf5ec864..fce308bcc81 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -1461,6 +1461,8 @@ inline bool fil_space_t::acquire_if_not_stopped() bool fil_crypt_must_default_encrypt() { + /* prevents a race condition with fil_crypt_set_rotate_key_age() */ + ut_ad(mutex_own(&fil_system.mutex)); return !srv_fil_crypt_rotate_key_age || !srv_encrypt_rotate; } @@ -2364,6 +2366,24 @@ fil_crypt_set_rotation_iops( os_event_set(fil_crypt_threads_event); } +/** Add the import tablespace to default_encrypt list +if necessary and signal fil_crypt_threads +@param space imported tablespace */ +void fil_crypt_add_imported_space(fil_space_t *space) +{ + mutex_enter(&fil_system.mutex); + + if (fil_crypt_must_default_encrypt()) + { + fil_system.default_encrypt_tables.push_back(*space); + space->is_in_default_encrypt= true; + } + + mutex_exit(&fil_system.mutex); + + os_event_set(fil_crypt_threads_event); +} + /********************************************************************* Adjust encrypt tables @param[in] val New setting for innodb-encrypt-tables */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 69ad47b8ac3..08229b21839 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -13286,7 +13286,7 @@ ha_innobase::discard_or_import_tablespace( | HA_STATUS_VARIABLE | HA_STATUS_AUTO); - fil_crypt_set_encrypt_tables(srv_encrypt_tables); + fil_crypt_add_imported_space(m_prebuilt->table->space); } } diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h index 62043003a6c..d8db6ad9851 100644 --- a/storage/innobase/include/fil0crypt.h +++ b/storage/innobase/include/fil0crypt.h @@ -383,6 +383,11 @@ void fil_crypt_set_rotation_iops( uint val); +/** Add the import tablespace to default_encrypt list +if necessary and signal fil_crypt_threads +@param space imported tablespace */ +void fil_crypt_add_imported_space(fil_space_t *space); + /********************************************************************* Adjust encrypt tables @param[in] val New setting for innodb-encrypt-tables */ From 001608de7e2273601b6b862a65225a8e15eab93f Mon Sep 17 00:00:00 2001 From: Brandon Nesterenko Date: Wed, 31 Jul 2024 14:14:18 -0600 Subject: [PATCH 16/17] MDEV-15393: Fix rpl_mysqldump_gtid_slave_pos The slave would try to sync_with_master_gtid.inc, but the master never actually saved its gtid position so the test would move on too quickly. --- mysql-test/suite/rpl/r/rpl_mysqldump_gtid_slave_pos.result | 1 + mysql-test/suite/rpl/t/rpl_mysqldump_gtid_slave_pos.test | 1 + 2 files changed, 2 insertions(+) diff --git a/mysql-test/suite/rpl/r/rpl_mysqldump_gtid_slave_pos.result b/mysql-test/suite/rpl/r/rpl_mysqldump_gtid_slave_pos.result index 301605d5d8d..1849f896758 100644 --- a/mysql-test/suite/rpl/r/rpl_mysqldump_gtid_slave_pos.result +++ b/mysql-test/suite/rpl/r/rpl_mysqldump_gtid_slave_pos.result @@ -30,6 +30,7 @@ insert into t1 set a = 4; insert into t1 set a = 3; insert into t1 set a = 2; insert into t1 set a = 1; +include/save_master_gtid.inc connection slave; include/start_slave.inc include/sync_with_master_gtid.inc diff --git a/mysql-test/suite/rpl/t/rpl_mysqldump_gtid_slave_pos.test b/mysql-test/suite/rpl/t/rpl_mysqldump_gtid_slave_pos.test index 74d231731c7..e66a92a6153 100644 --- a/mysql-test/suite/rpl/t/rpl_mysqldump_gtid_slave_pos.test +++ b/mysql-test/suite/rpl/t/rpl_mysqldump_gtid_slave_pos.test @@ -44,6 +44,7 @@ while ($i) eval insert into t1 set a = $i; --dec $i } +--source include/save_master_gtid.inc --connection slave --source include/start_slave.inc From 7a5b8bf0f5470a13094101f0a4bdfa9e1b9ded02 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Sat, 3 Aug 2024 08:47:17 +0200 Subject: [PATCH 17/17] lost in editinig line added --- mysql-test/main/json_debug_nonembedded_noasan.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/main/json_debug_nonembedded_noasan.test b/mysql-test/main/json_debug_nonembedded_noasan.test index 021abd8c602..11788fd3830 100644 --- a/mysql-test/main/json_debug_nonembedded_noasan.test +++ b/mysql-test/main/json_debug_nonembedded_noasan.test @@ -1,5 +1,6 @@ -- source include/not_embedded.inc --source include/have_debug.inc +--source include/not_asan.inc --echo # --echo # Beginning of 10.3 test