From f080863501972af381877c6c2335b8dcf3e87830 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Wed, 3 Mar 2021 15:37:03 +0530 Subject: [PATCH 1/8] MDEV-20648 InnoDB: Failing assertion: !(*node)->being_extended, innodb.log_data_file_size failed in buildbot, assertion `!space->is_stopping()' InnoDB should check whether the tablespace is being deleted while extending the tablespace. --- storage/innobase/fil/fil0fil.cc | 40 +++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index c71dbeff421..5adbd4df69e 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -1038,15 +1038,14 @@ fil_space_extend_must_retry( } -/*******************************************************************//** -Reserves the fil_system mutex and tries to make sure we can open at least one +/** Reserves the fil_system mutex and tries to make sure we can open at least one file while holding it. This should be called before calling -fil_node_prepare_for_io(), because that function may need to open a file. */ +fil_node_prepare_for_io(), because that function may need to open a file. +@param[in] space_id tablespace id +@return whether the tablespace is usable for io */ static -void -fil_mutex_enter_and_prepare_for_io( -/*===============================*/ - ulint space_id) /*!< in: space id */ +bool +fil_mutex_enter_and_prepare_for_io(ulint space_id) { for (ulint count = 0;;) { mutex_enter(&fil_system->mutex); @@ -1059,7 +1058,7 @@ fil_mutex_enter_and_prepare_for_io( fil_space_t* space = fil_space_get_by_id(space_id); if (space == NULL) { - break; + return false; } fil_node_t* node = UT_LIST_GET_LAST(space->chain); @@ -1074,6 +1073,10 @@ fil_mutex_enter_and_prepare_for_io( the insert buffer. The insert buffer is in tablespace 0, and we cannot end up waiting in this function. */ + } else if (space->is_stopping() && !space->is_being_truncated) { + /* If the tablespace is being deleted then InnoDB + shouldn't prepare the tablespace for i/o */ + return false; } else if (!node || node->is_open()) { /* If the file is already open, no need to do anything; if the space does not exist, we handle the @@ -1144,6 +1147,8 @@ fil_mutex_enter_and_prepare_for_io( break; } + + return true; } /** Try to extend a tablespace if it is smaller than the specified size. @@ -1160,7 +1165,10 @@ fil_space_extend( bool success; do { - fil_mutex_enter_and_prepare_for_io(space->id); + if (!fil_mutex_enter_and_prepare_for_io(space->id)) { + success = false; + break; + } } while (fil_space_extend_must_retry( space, UT_LIST_GET_LAST(space->chain), size, &success)); @@ -1537,7 +1545,9 @@ fil_space_t* fil_system_t::read_page0(ulint id) /* It is possible that the tablespace is dropped while we are not holding the mutex. */ - fil_mutex_enter_and_prepare_for_io(id); + if (!fil_mutex_enter_and_prepare_for_io(id)) { + return NULL; + } fil_space_t* space = fil_space_get_by_id(id); @@ -1610,14 +1620,16 @@ fil_space_get_first_path( ut_ad(fil_system); ut_a(id); - fil_mutex_enter_and_prepare_for_io(id); + if (!fil_mutex_enter_and_prepare_for_io(id)) { +fail_exit: + mutex_exit(&fil_system->mutex); + return(NULL); + } space = fil_space_get_space(id); if (space == NULL) { - mutex_exit(&fil_system->mutex); - - return(NULL); + goto fail_exit; } ut_ad(mutex_own(&fil_system->mutex)); From b044898b97729c36dd22e1133e47c92ed7c42e04 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 1 Mar 2021 21:16:13 +0530 Subject: [PATCH 2/8] MDEV-24748 extern column check missing in btr_index_rec_validate() In btr_index_rec_validate(), externally stored column check is missing while matching the length of the field with the length of the field data stored in record. Fetch the length of the externally stored part and compare it with the fixed field length. --- mysql-test/suite/innodb/r/innodb.result | 17 +++++++++++++++++ mysql-test/suite/innodb/t/innodb.test | 18 ++++++++++++++++++ storage/innobase/btr/btr0btr.cc | 12 ++++++++++++ 3 files changed, 47 insertions(+) diff --git a/mysql-test/suite/innodb/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result index ace226781c0..326aed06901 100644 --- a/mysql-test/suite/innodb/r/innodb.result +++ b/mysql-test/suite/innodb/r/innodb.result @@ -3373,3 +3373,20 @@ c1 c2 9 3 DROP TABLE t1; DROP TABLE t2; +# +# MDEV-24748 Extern field check missing +# in btr_index_rec_validate() +# +CREATE TABLE t1 (pk INT, c1 char(255), +c2 char(255), c3 char(255), c4 char(255), +c5 char(255), c6 char(255), c7 char(255), +c8 char(255), primary key (pk) +) CHARACTER SET utf32 ENGINE=InnoDB; +INSERT INTO t1 VALUES +(1, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'), +(2, 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'); +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +ALTER TABLE t1 FORCE; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test index 7aa146d7d99..d494f40bcb6 100644 --- a/mysql-test/suite/innodb/t/innodb.test +++ b/mysql-test/suite/innodb/t/innodb.test @@ -2628,3 +2628,21 @@ SELECT * FROM t2; DROP TABLE t1; DROP TABLE t2; + +--echo # +--echo # MDEV-24748 Extern field check missing +--echo # in btr_index_rec_validate() +--echo # +CREATE TABLE t1 (pk INT, c1 char(255), +c2 char(255), c3 char(255), c4 char(255), +c5 char(255), c6 char(255), c7 char(255), +c8 char(255), primary key (pk) +) CHARACTER SET utf32 ENGINE=InnoDB; + +INSERT INTO t1 VALUES + (1, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'), + (2, 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'); +CHECK TABLE t1; +ALTER TABLE t1 FORCE; +# Cleanup +DROP TABLE t1; diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 511ac66d58c..f7fe4413086 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -4519,6 +4519,18 @@ btr_index_rec_validate( rec_get_nth_field_offs(offsets, i, &len); + if (rec_offs_nth_extern(offsets, i)) { + + const byte* data = rec_get_nth_field( + rec, offsets, i, &len); + len -= BTR_EXTERN_FIELD_REF_SIZE; + ulint extern_len = mach_read_from_4( + data + len + BTR_EXTERN_LEN + 4); + if (fixed_size == extern_len) { + continue; + } + } + /* Note that if fixed_size != 0, it equals the length of a fixed-size column in the clustered index. We should adjust it here. From 08d8bce583227a25b4f646fa9a836f7893badd9a Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Wed, 3 Mar 2021 22:48:39 -0800 Subject: [PATCH 3/8] MDEV-22786 Crashes with nested table value constructors The bug caused crashes of the server when processing queries with nested table value constructors (TVC) . It happened because the grammar rules to parse TVC used the same global lists for both nested TVC and nesting TVC. As a result invalid select trees were constructed for queries with nested TVC and this led to crashes at the prepare stage. This patch provides its own lists structures for each TVC nest level. Besides the patch fixes a bug in the function wrap_tvc() that missed inheritance of the SELECT_LEX::exclude_from_table_unique_test for selects that wrapped TVCs. This inheritance is critical for specifications of derived tables that employ nested TVCs. Approved by dmitry.shulga@mariadb.com --- mysql-test/main/table_value_constr.result | 175 ++++++++++++++++++++++ mysql-test/main/table_value_constr.test | 106 +++++++++++++ sql/sql_lex.cc | 45 +++++- sql/sql_lex.h | 12 +- sql/sql_tvc.cc | 2 + sql/sql_yacc.yy | 3 +- sql/sql_yacc_ora.yy | 3 +- 7 files changed, 333 insertions(+), 13 deletions(-) diff --git a/mysql-test/main/table_value_constr.result b/mysql-test/main/table_value_constr.result index d2965ab1f6c..ff6d19a8e0e 100644 --- a/mysql-test/main/table_value_constr.result +++ b/mysql-test/main/table_value_constr.result @@ -2887,4 +2887,179 @@ drop table t1,t2,t3; select sum((values(1))); sum((values(1))) 1 +# +# MDEV-22786: Nested table values constructors +# +values ((values (2))); +(values (2)) +2 +values ((values (2)), (5), (select 4)); +(values (2)) 5 (select 4) +2 5 4 +values ((7), (values (2)), (5), (select 4)); +7 (values (2)) 5 (select 4) +7 2 5 4 +values ((values (2))) union values ((values (3))); +(values (2)) +2 +3 +values ((values (2))), ((values (3))); +(values (2)) +2 +3 +values ((values (2))), ((select 4)), ((values (3))); +(values (2)) +2 +4 +3 +values ((values (4)), (values (5))), ((values (1)), (values (7))); +(values (4)) (values (5)) +4 5 +1 7 +values ((values (4)), (select 5)), ((select 1), (values (7))); +(values (4)) (select 5) +4 5 +1 7 +values ((select 2)) union values ((values (3))); +(select 2) +2 +3 +values ((values (2))) union values((select 3)); +(values (2)) +2 +3 +values ((values (2))) union all values ((values (2))); +(values (2)) +2 +2 +values ((values (4)), (values (5))), ((values (1)), (values (7))) +union +values ((values (4)), (select 5)), ((select 2), (values (8))); +(values (4)) (values (5)) +4 5 +1 7 +2 8 +values ((values (4)), (values (5))), ((values (1)), (values (7))) +union all +values ((values (4)), (select 5)), ((select 2), (values (8))); +(values (4)) (values (5)) +4 5 +1 7 +4 5 +2 8 +values ((values (1) union values (1))); +(values (1) union values (1)) +1 +values ((values (1) union values (1) union values (1))); +(values (1) union values (1) union values (1)) +1 +values ((values ((values (4))))); +(values ((values (4)))) +4 +values ((values ((select 5)))); +(values ((select 5))) +5 +values ((select (values (4))), (values ((values(5))))); +(select (values (4))) (values ((values(5)))) +4 5 +values ((select (values (4))), (values ((select 5)))); +(select (values (4))) (values ((select 5))) +4 5 +values ((select (values (4))), (values ((values(5))))) +union +values ((select (values (4))), (values ((select 7)))); +(select (values (4))) (values ((values(5)))) +4 5 +4 7 +values ((values (2))), ((values ((values (4))))); +(values (2)) +2 +4 +values ((values (2))), ((values ((select 4)))); +(values (2)) +2 +4 +values ((values (2))), ((values ((values (4))))) +union +values ((values (8))), ((values ((select 4)))); +(values (2)) +2 +4 +8 +values ((values (2))), ((values ((values (4))))) +union all +values ((values (8))), ((values ((select 4)))); +(values (2)) +2 +4 +8 +4 +select * from (values ((values (2)))) dt; +(values (2)) +2 +select * from (values ((values (2)), (5), (select 4))) dt; +(values (2)) 5 (select 4) +2 5 4 +select * from (values ((values (2))) union values ((values (3)))) dt; +(values (2)) +2 +3 +select * from (values ((values (2))), ((values (3)))) dt; +(values (2)) +2 +3 +select * from (values ((values (2))), ((values (3)))) dt; +(values (2)) +2 +3 +select * from (values ((values (2))), ((select 4)), ((values (3)))) dt; +(values (2)) +2 +4 +3 +create table t1 (a int); +insert into t1 values (3), (7), (1); +values ((values ((select a from t1 where a=7)))); +(values ((select a from t1 where a=7))) +7 +values ((values ((select (values(2)) from t1 where a=8)))); +(values ((select (values(2)) from t1 where a=8))) +NULL +values ((values ((select a from t1 where a=7)))) +union +values ((values ((select (values(2)) from t1 where a=8)))); +(values ((select a from t1 where a=7))) +7 +NULL +values ((values ((select a from t1 where a in ((values (7))))))); +(values ((select a from t1 where a in ((values (7)))))) +7 +values ((values ((select a from t1 where a in ((values (7), (8))))))); +(values ((select a from t1 where a in ((values (7), (8)))))) +7 +values ((values +((select a from t1 where a in (values (7) union values (8)))))); +(values +((select a from t1 where a in (values (7) union values (8))))) +7 +values ((values ((select (values(2)) from t1 where a=8)))); +(values ((select (values(2)) from t1 where a=8))) +NULL +values ((select (values(2)) from t1 where a<7)); +ERROR 21000: Subquery returns more than 1 row +select * from (values ((values ((select a from t1 where a=7))))) dt; +(values ((select a from t1 where a=7))) +7 +select * from (values ((values ((select (values(2)) from t1 where a=8))))) dt; +(values ((select (values(2)) from t1 where a=8))) +NULL +insert into t1(a) values ((values (2))), ((values (3))); +select * from t1; +a +3 +7 +1 +2 +3 +drop table t1; End of 10.3 tests diff --git a/mysql-test/main/table_value_constr.test b/mysql-test/main/table_value_constr.test index 88d0ac2fbbf..3e976f88ed5 100644 --- a/mysql-test/main/table_value_constr.test +++ b/mysql-test/main/table_value_constr.test @@ -1522,4 +1522,110 @@ drop table t1,t2,t3; select sum((values(1))); +--echo # +--echo # MDEV-22786: Nested table values constructors +--echo # + +values ((values (2))); + +values ((values (2)), (5), (select 4)); + +values ((7), (values (2)), (5), (select 4)); + +values ((values (2))) union values ((values (3))); + +values ((values (2))), ((values (3))); + +values ((values (2))), ((select 4)), ((values (3))); + +values ((values (4)), (values (5))), ((values (1)), (values (7))); + +values ((values (4)), (select 5)), ((select 1), (values (7))); + +values ((select 2)) union values ((values (3))); + +values ((values (2))) union values((select 3)); + +values ((values (2))) union all values ((values (2))); + +values ((values (4)), (values (5))), ((values (1)), (values (7))) +union +values ((values (4)), (select 5)), ((select 2), (values (8))); + +values ((values (4)), (values (5))), ((values (1)), (values (7))) +union all +values ((values (4)), (select 5)), ((select 2), (values (8))); + +values ((values (1) union values (1))); + +values ((values (1) union values (1) union values (1))); + +values ((values ((values (4))))); + +values ((values ((select 5)))); + +values ((select (values (4))), (values ((values(5))))); + +values ((select (values (4))), (values ((select 5)))); + +values ((select (values (4))), (values ((values(5))))) +union +values ((select (values (4))), (values ((select 7)))); + +values ((values (2))), ((values ((values (4))))); + +values ((values (2))), ((values ((select 4)))); + +values ((values (2))), ((values ((values (4))))) +union +values ((values (8))), ((values ((select 4)))); + +values ((values (2))), ((values ((values (4))))) +union all +values ((values (8))), ((values ((select 4)))); + +select * from (values ((values (2)))) dt; + +select * from (values ((values (2)), (5), (select 4))) dt; + +select * from (values ((values (2))) union values ((values (3)))) dt; + +select * from (values ((values (2))), ((values (3)))) dt; + +select * from (values ((values (2))), ((values (3)))) dt; + +select * from (values ((values (2))), ((select 4)), ((values (3)))) dt; + +create table t1 (a int); +insert into t1 values (3), (7), (1); + +values ((values ((select a from t1 where a=7)))); + +values ((values ((select (values(2)) from t1 where a=8)))); + +values ((values ((select a from t1 where a=7)))) +union +values ((values ((select (values(2)) from t1 where a=8)))); + +values ((values ((select a from t1 where a in ((values (7))))))); + +values ((values ((select a from t1 where a in ((values (7), (8))))))); + +values ((values + ((select a from t1 where a in (values (7) union values (8)))))); + +values ((values ((select (values(2)) from t1 where a=8)))); + +--error ER_SUBQUERY_NO_1_ROW +values ((select (values(2)) from t1 where a<7)); + +select * from (values ((values ((select a from t1 where a=7))))) dt; + +select * from (values ((values ((select (values(2)) from t1 where a=8))))) dt; + +insert into t1(a) values ((values (2))), ((values (3))); +select * from t1; + +drop table t1; + --echo End of 10.3 tests diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 70d795c145d..c2bc8386404 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2421,6 +2421,8 @@ void st_select_lex::init_select() with_dep= 0; join= 0; lock_type= TL_READ_DEFAULT; + save_many_values.empty(); + save_insert_list= 0; tvc= 0; in_funcs.empty(); curr_tvc_name= 0; @@ -8302,16 +8304,52 @@ bool LEX::last_field_generated_always_as_row_end() } +void LEX::save_values_list_state() +{ + current_select->save_many_values= many_values; + current_select->save_insert_list= insert_list; +} + + +void LEX::restore_values_list_state() +{ + many_values= current_select->save_many_values; + insert_list= current_select->save_insert_list; +} + + +void LEX::tvc_start() +{ + if (current_select == &select_lex) + mysql_init_select(this); + else + save_values_list_state(); + many_values.empty(); + insert_list= 0; +} + + +bool LEX::tvc_start_derived() +{ + if (current_select->linkage == GLOBAL_OPTIONS_TYPE || + unlikely(mysql_new_select(this, 1, NULL))) + return true; + save_values_list_state(); + many_values.empty(); + insert_list= 0; + return false; +} + + bool LEX::tvc_finalize() { - mysql_init_select(this); if (unlikely(!(current_select->tvc= new (thd->mem_root) table_value_constr(many_values, current_select, current_select->options)))) return true; - many_values.empty(); + restore_values_list_state(); if (!current_select->master_unit()->fake_select_lex) current_select->master_unit()->add_fake_select_lex(thd); return false; @@ -8326,9 +8364,6 @@ bool LEX::tvc_finalize_derived() thd->parse_error(); return true; } - if (current_select->linkage == GLOBAL_OPTIONS_TYPE || - unlikely(mysql_new_select(this, 1, NULL))) - return true; current_select->linkage= DERIVED_TABLE_TYPE; return tvc_finalize(); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 979e212c1f6..474f3174ac9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1176,6 +1176,8 @@ public: /* it is for correct printing SELECT options */ thr_lock_type lock_type; + List save_many_values; + List *save_insert_list; table_value_constr *tvc; bool in_tvc; @@ -4046,12 +4048,10 @@ public: return false; } - void tvc_start() - { - field_list.empty(); - many_values.empty(); - insert_list= 0; - } + void save_values_list_state(); + void restore_values_list_state(); + void tvc_start(); + bool tvc_start_derived(); bool tvc_finalize(); bool tvc_finalize_derived(); diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc index cb056b0e15f..96c5223ee6a 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -673,6 +673,8 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl, wrapper_sl->nest_level= tvc_sl->nest_level; wrapper_sl->parsing_place= tvc_sl->parsing_place; wrapper_sl->linkage= tvc_sl->linkage; + wrapper_sl->exclude_from_table_unique_test= + tvc_sl->exclude_from_table_unique_test; lex->current_select= wrapper_sl; item= new (thd->mem_root) Item_field(thd, &wrapper_sl->context, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 88f12e97bfa..b26e2ddbf1b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -12334,7 +12334,8 @@ derived_query_specification: derived_table_value_constructor: VALUES { - Lex->tvc_start(); + if (Lex->tvc_start_derived()) + MYSQL_YYABORT; } values_list { diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index eaeaf2e5e7e..4af034db921 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -12272,7 +12272,8 @@ derived_query_specification: derived_table_value_constructor: VALUES { - Lex->tvc_start(); + if (Lex->tvc_start_derived()) + MYSQL_YYABORT; } values_list { From 5da6ffe22772897a55b1293f0f054b299e4bf539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Tue, 2 Mar 2021 15:37:12 +0200 Subject: [PATCH 4/8] MDEV-25032: Window functions without column references get removed from ORDER BY row_number() over () window function can be used without any column in the OVER clause. Additionally, the item doesn't reference any tables, as it's not effectively referencing any table. Rather it is specifically built based on the end temporary table used for window function computation. This caused remove_const function to wrongly drop it from the ORDER list. Effectively, we shouldn't be dropping any window function from the ORDER clause, so adjust remove_const to account for that. Reviewed by: Sergei Petrunia sergey@mariadb.com --- mysql-test/r/win.result | 26 +++++++++++++++++++ .../encryption/r/tempfiles_encrypted.result | 26 +++++++++++++++++++ mysql-test/t/win.test | 20 ++++++++++++++ sql/sql_select.cc | 1 + 4 files changed, 73 insertions(+) diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result index 3023a86eaad..dd74c5c77fd 100644 --- a/mysql-test/r/win.result +++ b/mysql-test/r/win.result @@ -3866,5 +3866,31 @@ NULL DROP VIEW v1; DROP TABLE t1,t2; # +# MDEV-25032 Window functions without column references get removed from ORDER BY +# +create table t1 (id int, score double); +insert into t1 values +(1, 5), +(1, 6), +(1, 6), +(1, 6), +(1, 7), +(1, 8.1), +(1, 9), +(1, 10); +select id, row_number() over () rn +from t1 +order by rn desc; +id rn +1 8 +1 7 +1 6 +1 5 +1 4 +1 3 +1 2 +1 1 +drop table t1; +# # End of 10.2 tests # diff --git a/mysql-test/suite/encryption/r/tempfiles_encrypted.result b/mysql-test/suite/encryption/r/tempfiles_encrypted.result index 1856c30a36b..27eedc45028 100644 --- a/mysql-test/suite/encryption/r/tempfiles_encrypted.result +++ b/mysql-test/suite/encryption/r/tempfiles_encrypted.result @@ -3872,6 +3872,32 @@ NULL DROP VIEW v1; DROP TABLE t1,t2; # +# MDEV-25032 Window functions without column references get removed from ORDER BY +# +create table t1 (id int, score double); +insert into t1 values +(1, 5), +(1, 6), +(1, 6), +(1, 6), +(1, 7), +(1, 8.1), +(1, 9), +(1, 10); +select id, row_number() over () rn +from t1 +order by rn desc; +id rn +1 8 +1 7 +1 6 +1 5 +1 4 +1 3 +1 2 +1 1 +drop table t1; +# # End of 10.2 tests # # diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test index c7e3dac598b..57214ab0165 100644 --- a/mysql-test/t/win.test +++ b/mysql-test/t/win.test @@ -2522,6 +2522,26 @@ SELECT NTH_VALUE(i1, i1) OVER (PARTITION BY i1) FROM v1; DROP VIEW v1; DROP TABLE t1,t2; +--echo # +--echo # MDEV-25032 Window functions without column references get removed from ORDER BY +--echo # + +create table t1 (id int, score double); +insert into t1 values +(1, 5), +(1, 6), +(1, 6), +(1, 6), +(1, 7), +(1, 8.1), +(1, 9), +(1, 10); +select id, row_number() over () rn +from t1 +order by rn desc; + +drop table t1; + --echo # --echo # End of 10.2 tests --echo # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f30ce088bc4..7bfbf719017 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12671,6 +12671,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, { table_map order_tables=order->item[0]->used_tables(); if (order->item[0]->with_sum_func || + order->item[0]->with_window_func || /* If the outer table of an outer join is const (either by itself or after applying WHERE condition), grouping on a field from such a From 978e48c96cf22b1f17444dd54b6b64b28752881e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 4 Mar 2021 17:15:38 +0200 Subject: [PATCH 5/8] MDEV-25051 Race condition between persistent statistics and RENAME TABLE or TRUNCATE innobase_rename_table(): Invoke dict_stats_wait_bg_to_stop_using_table() to ensure that dict_stats_update() cannot be accessing the table name that we will be modifying. If we are executing RENAME rather than TRUNCATE, reset the flag at the end so that persistent statistics can be calculated again. The race condition was encountered with ASAN and rr. Sorry, there is no test case, like there is for nothing related to dict_stats_wait_bg_to_stop_using_table(). The entire code is an ugly work-around for the failure of dict_stats_process_entry_from_recalc_pool() to acquire MDL. Note: It appears that an ALTER TABLE that is not rebuilding the table will fail to reset the flag that blocks the processing of statistics. --- storage/innobase/handler/ha_innodb.cc | 32 +++++++++++++++------------ 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c67bf6bd607..11d8ec2b81e 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -13518,17 +13518,10 @@ innobase_drop_database( @param[in,out] trx InnoDB data dictionary transaction @param[in] from old table name @param[in] to new table name -@param[in] commit whether to commit trx -@param[in] use_fk whether to parse and enforce FOREIGN KEY constraints +@param[in] commit whether to commit trx (and to enforce FOREIGN KEY) @return DB_SUCCESS or error code */ -inline -dberr_t -innobase_rename_table( - trx_t* trx, - const char* from, - const char* to, - bool commit, - bool use_fk) +inline dberr_t innobase_rename_table(trx_t *trx, const char *from, + const char *to, bool commit) { dberr_t error; char norm_to[FN_REFLEN]; @@ -13561,6 +13554,9 @@ innobase_rename_table( Convert lock_wait_timeout unit from second to 250 milliseconds */ long int lock_wait_timeout = thd_lock_wait_timeout(trx->mysql_thd) * 4; if (table != NULL) { + if (commit) { + dict_stats_wait_bg_to_stop_using_table(table, trx); + } for (dict_index_t* index = dict_table_get_first_index(table); index != NULL; index = dict_table_get_next_index(index)) { @@ -13574,7 +13570,9 @@ innobase_rename_table( } } } - dict_table_close(table, TRUE, FALSE); + if (!commit) { + dict_table_close(table, TRUE, FALSE); + } } /* FTS sync is in progress. We shall timeout this operation */ @@ -13589,7 +13587,7 @@ innobase_rename_table( ut_a(trx->will_lock > 0); error = row_rename_table_for_mysql(norm_from, norm_to, trx, commit, - use_fk); + commit); if (error != DB_SUCCESS) { if (error == DB_TABLE_NOT_FOUND @@ -13641,6 +13639,10 @@ innobase_rename_table( func_exit: if (commit) { + if (table) { + table->stats_bg_flag &= ~BG_STAT_SHOULD_QUIT; + dict_table_close(table, TRUE, FALSE); + } row_mysql_unlock_data_dictionary(trx); } @@ -13726,9 +13728,11 @@ int ha_innobase::truncate() ++trx->will_lock; trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); row_mysql_lock_data_dictionary(trx); + dict_stats_wait_bg_to_stop_using_table(ib_table, trx); + int err = convert_error_code_to_mysql( innobase_rename_table(trx, ib_table->name.m_name, temp_name, - false, false), + false), ib_table->flags, m_user_thd); if (err) { trx_rollback_for_mysql(trx); @@ -13811,7 +13815,7 @@ ha_innobase::rename_table( ++trx->will_lock; trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); - dberr_t error = innobase_rename_table(trx, from, to, true, true); + dberr_t error = innobase_rename_table(trx, from, to, true); DEBUG_SYNC(thd, "after_innobase_rename_table"); From 7759991a06d54630214f19eaa0ec39bd21bf09df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 4 Mar 2021 18:11:25 +0200 Subject: [PATCH 6/8] fixup 58b56f14a096285a0e51b2233fc35398f1b01f5a: Remove dead code row_prebuilt_t::m_no_prefetch: Remove (it was always false). row_prebuilt_t::m_read_virtual_key: Remove (it was always false). Only ha_innopart ever set these fields. --- storage/innobase/include/row0mysql.h | 8 +------- storage/innobase/row/row0mysql.cc | 5 +---- storage/innobase/row/row0sel.cc | 26 ++++---------------------- 3 files changed, 6 insertions(+), 33 deletions(-) diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index d5cdd4a3f17..8738f991368 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2000, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 2021, 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 the Free Software @@ -784,12 +784,6 @@ struct row_prebuilt_t { search key values from MySQL format to InnoDB format.*/ uint srch_key_val_len; /*!< Size of search key */ - /** Disable prefetch. */ - bool m_no_prefetch; - - /** Return materialized key for secondary index scan */ - bool m_read_virtual_key; - /** The MySQL table object */ TABLE* m_mysql_table; }; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 312c35c58a3..c2f9186d408 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2000, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2020, MariaDB Corporation. +Copyright (c) 2015, 2021, 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 the Free Software @@ -958,9 +958,6 @@ row_create_prebuilt( prebuilt->fts_doc_id_in_read_set = 0; prebuilt->blob_heap = NULL; - prebuilt->m_no_prefetch = false; - prebuilt->m_read_virtual_key = false; - DBUG_RETURN(prebuilt); } diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 0451a240ffc..864f7bd54ab 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -2,7 +2,7 @@ Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. -Copyright (c) 2015, 2020, MariaDB Corporation. +Copyright (c) 2015, 2021, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -3168,8 +3168,7 @@ static bool row_sel_store_mysql_rec( search or virtual key read is not requested. */ if (!rec_clust || !prebuilt->index->has_virtual() - || (!prebuilt->read_just_key - && !prebuilt->m_read_virtual_key)) { + || !prebuilt->read_just_key) { /* Initialize the NULL bit. */ mysql_rec[templ->mysql_null_byte_offset] |= (byte) templ->mysql_null_bit_mask; @@ -3185,23 +3184,8 @@ static bool row_sel_store_mysql_rec( const dfield_t* dfield = dtuple_get_nth_v_field( vrow, col->v_pos); - /* If this is a partitioned table, it might request - InnoDB to fill out virtual column data for serach - index key values while other non key columns are also - getting selected. The non-key virtual columns may - not be materialized and we should skip them. */ if (dfield_get_type(dfield)->mtype == DATA_MISSING) { -#ifdef UNIV_DEBUG - ulint prefix; -#endif /* UNIV_DEBUG */ - ut_ad(prebuilt->m_read_virtual_key); - - /* If it is part of index key the data should - have been materialized. */ - ut_ad(dict_index_get_nth_col_or_prefix_pos( - prebuilt->index, col->v_pos, false, - true, &prefix) == ULINT_UNDEFINED); - + ut_ad("no ha_innopart in MariaDB" == 0); continue; } @@ -4377,8 +4361,7 @@ row_search_mvcc( index key, if this is covered index scan or virtual key read is requested. */ bool need_vrow = dict_index_has_virtual(prebuilt->index) - && (prebuilt->read_just_key - || prebuilt->m_read_virtual_key); + && prebuilt->read_just_key; /* Reset the new record lock info if srv_locks_unsafe_for_binlog is set or session is using a READ COMMITED isolation level. Then @@ -5524,7 +5507,6 @@ use_covering_index: if ((match_mode == ROW_SEL_EXACT || prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD) && prebuilt->select_lock_type == LOCK_NONE - && !prebuilt->m_no_prefetch && !prebuilt->templ_contains_blob && !prebuilt->clust_index_was_generated && !prebuilt->used_in_HANDLER From 545cba13eb4e013363a126754c040c335874c386 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 4 Mar 2021 23:09:22 +0100 Subject: [PATCH 7/8] MDEV-22929 fixup. Print "completed OK!" if page corruption and --log-innodb-page-corruption Since we do not stop at corrupted page error, there is no reason to log a backup error. --- extra/mariabackup/xtrabackup.cc | 7 +++---- .../mariabackup/log_page_corruption.result | 7 ++++--- .../suite/mariabackup/log_page_corruption.test | 18 +++++++++++------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 53301fd8e75..ffb09c73edb 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4718,13 +4718,12 @@ fail_before_log_copying_thread_start: log_file_op = NULL; pthread_mutex_destroy(&backup_mutex); pthread_cond_destroy(&scanned_lsn_cond); - if (opt_log_innodb_page_corruption && !corrupted_pages.empty()) { + if (!corrupted_pages.empty()) { + ut_ad(opt_log_innodb_page_corruption); msg("Error: corrupted innodb pages are found and logged to " MB_CORRUPTED_PAGES_FILE " file"); - return false; } - else - return(true); + return(true); } diff --git a/mysql-test/suite/mariabackup/log_page_corruption.result b/mysql-test/suite/mariabackup/log_page_corruption.result index 13e373b2f70..01ad4422c6a 100644 --- a/mysql-test/suite/mariabackup/log_page_corruption.result +++ b/mysql-test/suite/mariabackup/log_page_corruption.result @@ -22,11 +22,12 @@ INSERT INTO t5_corrupted_to_rename VALUES (3), (4), (5), (6), (7), (8), (9); INSERT INTO t6_corrupted_to_drop VALUES (3), (4), (5), (6), (7), (8), (9); INSERT INTO t7_corrupted_to_alter VALUES (3), (4), (5), (6), (7), (8), (9); # Corrupt tables -# Backup must fail due to page corruption +# Backup must fail due to page corruption FOUND 1 /Database page corruption detected.*/ in backup.log # "innodb_corrupted_pages" file must not exist -# Backup must fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option +# Backup must not fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option FOUND 1 /Database page corruption detected.*/ in backup.log +FOUND 1 /completed OK!/ in backup.log --- "innodb_corrupted_pages" file content: --- test/t1_corrupted 6 8 9 @@ -42,7 +43,7 @@ test/t7_corrupted_to_alter INSERT INTO t1_inc_corrupted VALUES (3), (4), (5), (6), (7), (8), (9); INSERT INTO t2_inc_corrupted VALUES (3), (4), (5), (6), (7), (8), (9); INSERT INTO t3_inc VALUES (3), (4), (5), (6), (7), (8), (9); -# Backup must fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option +# Backup must not fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option --- "innodb_corrupted_pages" file content: --- test/t1_corrupted 6 8 9 diff --git a/mysql-test/suite/mariabackup/log_page_corruption.test b/mysql-test/suite/mariabackup/log_page_corruption.test index e9419687288..0151afb96b4 100644 --- a/mysql-test/suite/mariabackup/log_page_corruption.test +++ b/mysql-test/suite/mariabackup/log_page_corruption.test @@ -59,7 +59,7 @@ EOF --let corrupted_pages_file_filt = $MYSQLTEST_VARDIR/tmp/innodb_corrupted_pages_filt --let perl_result_file=$MYSQLTEST_VARDIR/tmp/perl_result ---echo # Backup must fail due to page corruption +--echo # Backup must fail due to page corruption --disable_result_log --error 1 exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir > $backuplog; @@ -80,15 +80,19 @@ exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir= --let after_copy_test_t7_corrupted_to_alter=ALTER TABLE test.t7_corrupted_to_alter ADD COLUMN (d INT) --let add_corrupted_page_for_test_t7_corrupted_to_alter=3 ---echo # Backup must fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option +--echo # Backup must not fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option --disable_result_log ---error 1 --exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --log-innodb-page-corruption --target-dir=$targetdir --dbug=+d,mariabackup_events,mariabackup_inject_code > $backuplog --enable_result_log --let SEARCH_PATTERN=Database page corruption detected.* --let SEARCH_FILE=$backuplog --source include/search_pattern_in_file.inc + +--let SEARCH_PATTERN=completed OK! +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc + --echo --- "innodb_corrupted_pages" file content: --- perl; do "$ENV{MTR_SUITE_DIR}/include/corrupt-page.pl"; @@ -145,9 +149,8 @@ EOF --let after_copy_test_t7_inc_corrupted_to_alter=ALTER TABLE test.t7_inc_corrupted_to_alter ADD COLUMN (d INT) --let add_corrupted_page_for_test_t7_inc_corrupted_to_alter=3 ---echo # Backup must fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option +--echo # Backup must not fail, but "innodb_corrupted_pages" file must be created due to --log-innodb-page-corruption option --disable_result_log ---error 1 --exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --log-innodb-page-corruption --target-dir=$incdir --incremental-basedir=$targetdir --dbug=+d,mariabackup_events,mariabackup_inject_code > $backuplog --disable_result_log @@ -161,6 +164,9 @@ EOF --let SEARCH_PATTERN=Database page corruption detected.* --let SEARCH_FILE=$backuplog --source include/search_pattern_in_file.inc +--let SEARCH_PATTERN=completed OK! +--source include/search_pattern_in_file.inc + --let corrupted_pages_file = $incdir/innodb_corrupted_pages --echo --- "innodb_corrupted_pages" file content: --- perl; @@ -260,7 +266,6 @@ EOF --echo # Full backup with --log-innodb-page-corruption --disable_result_log ---error 1 --exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --log-innodb-page-corruption --target-dir=$targetdir --enable_result_log --let corrupted_pages_file = $targetdir/innodb_corrupted_pages @@ -288,7 +293,6 @@ EOF --echo # Incremental backup --log-innodb-page-corruption --disable_result_log ---error 1 --exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --log-innodb-page-corruption --target-dir=$incdir --incremental-basedir=$targetdir --dbug=+d,mariabackup_events,mariabackup_inject_code > $backuplog --disable_result_log --let corrupted_pages_file = $incdir/innodb_corrupted_pages From ecc1cd219d427e62acbd37c4c02e1f99d6c2d769 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 5 Mar 2021 14:12:35 +0200 Subject: [PATCH 8/8] Fixed that unit.pcre_test works again. --- mysql-test/suite/unit/suite.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/unit/suite.pm b/mysql-test/suite/unit/suite.pm index 43c9e115de6..53f8923777a 100644 --- a/mysql-test/suite/unit/suite.pm +++ b/mysql-test/suite/unit/suite.pm @@ -48,10 +48,10 @@ sub start_test { my ($command, %tests, $prefix); for (@ctest_list) { chomp; - if (/^\d+: Test command: +([^ \t]+)/) { + if (/^\d+: Test command: +([^ \t]+.*)/) { $command= $1; $prefix= /libmariadb/ ? 'conc_' : ''; - } elsif (/^ +Test +#\d+: ([^ \t]+)/) { + } elsif (/^ +Test +#\d+: ([^ \t]+.*)/) { if ($command ne "NOT_AVAILABLE" && $command ne "/bin/sh") { $tests{$prefix.$1}=$command; }