From 393cf51c045878c717ee7e17478755d093675802 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 23 Apr 2021 19:28:48 +0300 Subject: [PATCH 1/8] MDEV-24925: Server crashes in Item_subselect::init_expr_cache_tracker The optimizer removes redundant GROUP BY operations. If GROUP BY element is a subselect, it is "eliminated". However one must not eliminate the item if it is used both in the select list and in the GROUP BY, like so: select (select ... ) as SUBQ from ... group by SUBQ Do not eliminate such items. --- mysql-test/main/subselect4.result | 50 +++++++++++++++++++++++++++++++ mysql-test/main/subselect4.test | 32 ++++++++++++++++++++ sql/sql_select.cc | 11 ++++++- 3 files changed, 92 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/subselect4.result b/mysql-test/main/subselect4.result index 156e78e7778..456b9bcd829 100644 --- a/mysql-test/main/subselect4.result +++ b/mysql-test/main/subselect4.result @@ -2786,4 +2786,54 @@ id select_type table type possible_keys key key_len ref rows Extra set names default; set @@in_predicate_conversion_threshold= @save_in_predicate_conversion_threshold; DROP TABLE t1,t2; +# +# MDEV-24925: Server crashes in Item_subselect::init_expr_cache_tracker +# +CREATE TABLE t1 (id INT PRIMARY KEY); +INSERT INTO t1 VALUES (1),(2); +SELECT +1 IN ( +SELECT +(SELECT COUNT(id) +FROM t1 +WHERE t1_outer.id <> id +) AS f +FROM +t1 AS t1_outer +GROUP BY f +); +1 IN ( +SELECT +(SELECT COUNT(id) +FROM t1 +WHERE t1_outer.id <> id +) AS f +FROM +t1 AS t1_outer +GROUP BY f +) +1 +SELECT +1 IN ( +SELECT +(SELECT COUNT(id) +FROM t1 +WHERE t1_outer.id <> id +) AS f +FROM +t1 AS t1_outer +GROUP BY 1 +); +1 IN ( +SELECT +(SELECT COUNT(id) +FROM t1 +WHERE t1_outer.id <> id +) AS f +FROM +t1 AS t1_outer +GROUP BY 1 +) +1 +DROP TABLE t1; # End of 10.3 tests diff --git a/mysql-test/main/subselect4.test b/mysql-test/main/subselect4.test index a5fcc507905..ab311d3e505 100644 --- a/mysql-test/main/subselect4.test +++ b/mysql-test/main/subselect4.test @@ -2308,4 +2308,36 @@ set names default; set @@in_predicate_conversion_threshold= @save_in_predicate_conversion_threshold; DROP TABLE t1,t2; +--echo # +--echo # MDEV-24925: Server crashes in Item_subselect::init_expr_cache_tracker +--echo # +CREATE TABLE t1 (id INT PRIMARY KEY); +INSERT INTO t1 VALUES (1),(2); + +SELECT + 1 IN ( + SELECT + (SELECT COUNT(id) + FROM t1 + WHERE t1_outer.id <> id + ) AS f + FROM + t1 AS t1_outer + GROUP BY f + ); + +SELECT + 1 IN ( + SELECT + (SELECT COUNT(id) + FROM t1 + WHERE t1_outer.id <> id + ) AS f + FROM + t1 AS t1_outer + GROUP BY 1 + ); + +DROP TABLE t1; + --echo # End of 10.3 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b4e6c505261..d53c592ff7b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -596,7 +596,16 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) { for (ORDER *ord= subq_select_lex->group_list.first; ord; ord= ord->next) { - (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL); + /* + Do not remove the item if it is used in select list and then referred + from GROUP BY clause by its name or number. Example: + + select (select ... ) as SUBQ ... group by SUBQ + + Here SUBQ cannot be removed. + */ + if (!ord->in_field_list) + (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL); } subq_select_lex->join->group_list= NULL; subq_select_lex->group_list.empty(); From 42aad65b895dff937aa0618b3237eb4f653ce0e4 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 23 Apr 2021 19:45:09 +0300 Subject: [PATCH 2/8] MDEV-24898: Server crashes in st_select_lex::next_select Add a testcase --- mysql-test/main/subselect4.result | 11 +++++++++++ mysql-test/main/subselect4.test | 13 +++++++++++++ 2 files changed, 24 insertions(+) diff --git a/mysql-test/main/subselect4.result b/mysql-test/main/subselect4.result index 456b9bcd829..6940795a9c1 100644 --- a/mysql-test/main/subselect4.result +++ b/mysql-test/main/subselect4.result @@ -2836,4 +2836,15 @@ GROUP BY 1 ) 1 DROP TABLE t1; +# +# MDEV-24898: Server crashes in st_select_lex::next_select / Item_subselect::is_expensive +# (Testcase) +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (3),(4); +SELECT 1 IN (SELECT (SELECT a FROM t1) AS x FROM t2 GROUP BY x); +ERROR 21000: Subquery returns more than 1 row +drop table t1,t2; # End of 10.3 tests diff --git a/mysql-test/main/subselect4.test b/mysql-test/main/subselect4.test index ab311d3e505..31f6f55b4e4 100644 --- a/mysql-test/main/subselect4.test +++ b/mysql-test/main/subselect4.test @@ -2340,4 +2340,17 @@ SELECT DROP TABLE t1; +--echo # +--echo # MDEV-24898: Server crashes in st_select_lex::next_select / Item_subselect::is_expensive +--echo # (Testcase) +--echo # +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); # Optional, fails either way +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (3),(4); # Optional, fails either way + +--error ER_SUBQUERY_NO_1_ROW +SELECT 1 IN (SELECT (SELECT a FROM t1) AS x FROM t2 GROUP BY x); +drop table t1,t2; + --echo # End of 10.3 tests From c72c77ca3bcb9d29903f95bf37c9930224984d29 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 23 Apr 2021 19:28:48 +0300 Subject: [PATCH 3/8] MDEV-24925: Server crashes in Item_subselect::init_expr_cache_tracker (trivial backport to 10.2) The optimizer removes redundant GROUP BY operations. If GROUP BY element is a subselect, it is "eliminated". However one must not eliminate the item if it is used both in the select list and in the GROUP BY, like so: select (select ... ) as SUBQ from ... group by SUBQ Do not eliminate such items. --- mysql-test/r/subselect4.result | 50 ++++++++++++++++++++++++++++++++++ mysql-test/t/subselect4.test | 32 ++++++++++++++++++++++ sql/sql_select.cc | 11 +++++++- 3 files changed, 92 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index 2e24cbcb40c..ef75bd97fcc 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -2722,3 +2722,53 @@ SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2); a DROP TABLE t1,t2; # End of 10.2 tests +# +# MDEV-24925: Server crashes in Item_subselect::init_expr_cache_tracker +# +CREATE TABLE t1 (id INT PRIMARY KEY); +INSERT INTO t1 VALUES (1),(2); +SELECT +1 IN ( +SELECT +(SELECT COUNT(id) +FROM t1 +WHERE t1_outer.id <> id +) AS f +FROM +t1 AS t1_outer +GROUP BY f +); +1 IN ( +SELECT +(SELECT COUNT(id) +FROM t1 +WHERE t1_outer.id <> id +) AS f +FROM +t1 AS t1_outer +GROUP BY f +) +1 +SELECT +1 IN ( +SELECT +(SELECT COUNT(id) +FROM t1 +WHERE t1_outer.id <> id +) AS f +FROM +t1 AS t1_outer +GROUP BY 1 +); +1 IN ( +SELECT +(SELECT COUNT(id) +FROM t1 +WHERE t1_outer.id <> id +) AS f +FROM +t1 AS t1_outer +GROUP BY 1 +) +1 +DROP TABLE t1; diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index f19a654de64..dae9e71fd92 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -2237,3 +2237,35 @@ SELECT a FROM t1 WHERE (a, a) IN (SELECT 1, 2) AND a = (SELECT MIN(b) FROM t2); DROP TABLE t1,t2; --echo # End of 10.2 tests + +--echo # +--echo # MDEV-24925: Server crashes in Item_subselect::init_expr_cache_tracker +--echo # +CREATE TABLE t1 (id INT PRIMARY KEY); +INSERT INTO t1 VALUES (1),(2); + +SELECT + 1 IN ( + SELECT + (SELECT COUNT(id) + FROM t1 + WHERE t1_outer.id <> id + ) AS f + FROM + t1 AS t1_outer + GROUP BY f + ); + +SELECT + 1 IN ( + SELECT + (SELECT COUNT(id) + FROM t1 + WHERE t1_outer.id <> id + ) AS f + FROM + t1 AS t1_outer + GROUP BY 1 + ); + +DROP TABLE t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 90c071803a1..b85bd31e23c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -585,7 +585,16 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) { for (ORDER *ord= subq_select_lex->group_list.first; ord; ord= ord->next) { - (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL); + /* + Do not remove the item if it is used in select list and then referred + from GROUP BY clause by its name or number. Example: + + select (select ... ) as SUBQ ... group by SUBQ + + Here SUBQ cannot be removed. + */ + if (!ord->in_field_list) + (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL); } subq_select_lex->join->group_list= NULL; subq_select_lex->group_list.empty(); From 2f6912dabcb85382eea004f590ad51815c20e5c5 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 23 Apr 2021 19:45:09 +0300 Subject: [PATCH 4/8] MDEV-24898: Server crashes in st_select_lex::next_select (trivial backport to 10.2) Add a testcase --- mysql-test/r/subselect4.result | 11 +++++++++++ mysql-test/t/subselect4.test | 13 +++++++++++++ 2 files changed, 24 insertions(+) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index ef75bd97fcc..4021f717964 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -2772,3 +2772,14 @@ GROUP BY 1 ) 1 DROP TABLE t1; +# +# MDEV-24898: Server crashes in st_select_lex::next_select / Item_subselect::is_expensive +# (Testcase) +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (3),(4); +SELECT 1 IN (SELECT (SELECT a FROM t1) AS x FROM t2 GROUP BY x); +ERROR 21000: Subquery returns more than 1 row +drop table t1,t2; diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index dae9e71fd92..e218e3aab18 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -2269,3 +2269,16 @@ SELECT ); DROP TABLE t1; + +--echo # +--echo # MDEV-24898: Server crashes in st_select_lex::next_select / Item_subselect::is_expensive +--echo # (Testcase) +--echo # +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); # Optional, fails either way +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (3),(4); # Optional, fails either way + +--error ER_SUBQUERY_NO_1_ROW +SELECT 1 IN (SELECT (SELECT a FROM t1) AS x FROM t2 GROUP BY x); +drop table t1,t2; From 391f1aa6ee8ec6487898b1bb04424965279f2404 Mon Sep 17 00:00:00 2001 From: Sujatha Date: Fri, 5 Feb 2021 16:45:35 +0530 Subject: [PATCH 5/8] MDEV-24773: slave_compressed_protocol doesn't work properly with semi-sync replication Back port upstream fix commit 1800b015a1d487330f7b15f2020b887be348a66b Author: Venkatesh Duggirala Date: Fri Sep 8 20:29:22 2017 +0530 Bug#26027024 SLAVE_COMPRESSED_PROTOCOL DOESN'T WORK WITH SEMI-SYNC REPLICATION IN MYSQL-5.7 Analysis: In mysql-5.6, dump thread (the thread that is created on Master after Slave requested for a binlog dump) is also used to receive acknowledgements from the Slave and act on them accordingly. For performance reasons, a special thread called Ack Receiver thread is added in mysql-5.7 Semi synchronous replication plugin. This thread does not have special handling to receive acknowledgements if Slave has enabled compression in the protocol. Hence Master is unable to handle any slave if Slave_compressed_protocol is enabled on it. Fix: Enable compress flag on the communication channels if the Slave has Slave_compressed_protocol ON. --- ...semi_sync_slave_compressed_protocol.result | 19 +++++++ ...i_sync_slave_compressed_protocol-slave.opt | 1 + ...l_semi_sync_slave_compressed_protocol.test | 55 +++++++++++++++++++ sql/semisync_master_ack_receiver.cc | 5 ++ 4 files changed, 80 insertions(+) create mode 100644 mysql-test/suite/rpl/r/rpl_semi_sync_slave_compressed_protocol.result create mode 100644 mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol-slave.opt create mode 100644 mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol.test diff --git a/mysql-test/suite/rpl/r/rpl_semi_sync_slave_compressed_protocol.result b/mysql-test/suite/rpl/r/rpl_semi_sync_slave_compressed_protocol.result new file mode 100644 index 00000000000..b0fe083f928 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_semi_sync_slave_compressed_protocol.result @@ -0,0 +1,19 @@ +include/master-slave.inc +[connection master] +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; +connection slave; +include/stop_slave.inc +SET @@GLOBAL.rpl_semi_sync_slave_enabled = 1; +include/start_slave.inc +connection master; +CREATE TABLE t1 (i INT); +DROP TABLE t1; +include/rpl_sync.inc +include/assert_grep.inc [Check that there is no 'Read semi-sync reply magic number error' in error log.] +connection master; +SET @@GLOBAL. rpl_semi_sync_master_enabled = $sav_enabled_master; +connection slave; +include/stop_slave.inc +SET @@GLOBAL. rpl_semi_sync_slave_enabled = $sav_enabled_slave; +include/start_slave.inc +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol-slave.opt b/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol-slave.opt new file mode 100644 index 00000000000..a1b687d691e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol-slave.opt @@ -0,0 +1 @@ +--slave_compressed_protocol diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol.test b/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol.test new file mode 100644 index 00000000000..bc05bec2a96 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_semi_sync_slave_compressed_protocol.test @@ -0,0 +1,55 @@ +################################################################################ +# Bug#26027024 SLAVE_COMPRESSED_PROTOCOL DOESN'T WORK WITH SEMI-SYNC +# REPLICATION IN MYSQL-5.7 +# +# Steps to reproduce: +# 1) Set slave_compressed_protocol ON on Slave. +# 2) Do some sample work on Master +# 3) After the work is synced on Slave, check that there is no error +# (Read semi-sync reply magic number error) on Slave. +# 4) Cleanup +################################################################################ +# Test is independent of Binlog format. One of the three formats is enough +# for testing. Choosing 'Row' format. +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +--let $sav_enabled_master=`SELECT @@GLOBAL.rpl_semi_sync_master_enabled ` +SET @@GLOBAL.rpl_semi_sync_master_enabled = 1; + +--connection slave +source include/stop_slave.inc; +--let $sav_enabled_slave=`SELECT @@GLOBAL.rpl_semi_sync_slave_enabled ` +SET @@GLOBAL.rpl_semi_sync_slave_enabled = 1; +source include/start_slave.inc; + +--connection master +# Do some sample work on Master with slave_compressed_protocol ON. +# (slave_compressed_protocol is set to ON in -slave.opt file of this test.) +CREATE TABLE t1 (i INT); +DROP TABLE t1; + +# Make sure sync is done, so that next 'assert' step can be executed without +# any issues. +--source include/rpl_sync.inc + +# Without the fix, the test would have generated few +# errors in the error log. With the fix, test will +# pass without any errors in the error log. +--let $assert_text= Check that there is no 'Read semi-sync reply magic number error' in error log. +--let $assert_select=Read semi-sync reply magic number error +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err +--let $assert_count= 0 +--let $assert_only_after = CURRENT_TEST:rpl.rpl_semi_sync_slave_compressed_protocol.test +--source include/assert_grep.inc + +--connection master +--evalp SET @@GLOBAL. rpl_semi_sync_master_enabled = $sav_enabled_master + +--connection slave +source include/stop_slave.inc; +--evalp SET @@GLOBAL. rpl_semi_sync_slave_enabled = $sav_enabled_slave +source include/start_slave.inc; + +# Cleanup +--source include/rpl_end.inc diff --git a/sql/semisync_master_ack_receiver.cc b/sql/semisync_master_ack_receiver.cc index 81f494c9d34..cc3a56a56b2 100644 --- a/sql/semisync_master_ack_receiver.cc +++ b/sql/semisync_master_ack_receiver.cc @@ -268,6 +268,11 @@ void Ack_receiver::run() net_clear(&net, 0); net.vio= &slave->vio; + /* + Set compress flag. This is needed to support + Slave_compress_protocol flag enabled Slaves + */ + net.compress= slave->thd->net.compress; len= my_net_read(&net); if (likely(len != packet_error)) From 4d412e9854ccb3676a9a51a002fbcc6b44a26294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 26 Apr 2021 18:17:18 +0300 Subject: [PATCH 6/8] MDEV-24758 heap-use-after-poison in innobase_add_instant_try/rec_copy This is a backport of commit fd9ca2a742abe2e91b2b77e70915dec7bd3cd7e1 (MDEV-23295) and commit 9a156e1a23046ba3e37bdb1e4e1ad887d3f5829b (MDEV-23345) to 10.3. An instant ADD/DROP/reorder column could create a dummy table object with the wrong ROW_FORMAT when innodb_default_row_format was changed between CREATE TABLE and ALTER TABLE. prepare_inplace_alter_table_dict(): If we had promised that ALGORITHM=INPLACE is supported, we must preserve the ROW_FORMAT. The rest of the changes are related to adding Alter_inplace_info::inplace_supported to cache the return value of handler::check_if_supported_inplace_alter(). --- .../innodb/r/default_row_format_alter.result | 10 ++++++++++ .../suite/innodb/t/default_row_format_alter.test | 14 ++++++++++++++ sql/handler.h | 3 +++ sql/sql_alter.cc | 10 +++++----- sql/sql_alter.h | 9 +++------ sql/sql_table.cc | 16 ++++++++-------- storage/innobase/handler/handler0alter.cc | 13 +++++++++++++ 7 files changed, 56 insertions(+), 19 deletions(-) diff --git a/mysql-test/suite/innodb/r/default_row_format_alter.result b/mysql-test/suite/innodb/r/default_row_format_alter.result index 1f349e6e2f6..9d96edcf79c 100644 --- a/mysql-test/suite/innodb/r/default_row_format_alter.result +++ b/mysql-test/suite/innodb/r/default_row_format_alter.result @@ -82,4 +82,14 @@ SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary t1 InnoDB # Compact # # # # # # NULL # # NULL latin1_swedish_ci NULL 0 N DROP TABLE t1; +# +# MDEV-24758 heap-use-after-poison in innobase_add_instant_try/rec_copy +# +CREATE TABLE t1 (pk INT PRIMARY KEY) CHARACTER SET utf8 ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +SET GLOBAL innodb_default_row_format = REDUNDANT; +ALTER TABLE t1 ADD a CHAR(8) DEFAULT ''; +DROP TABLE t1; +SET GLOBAL innodb_default_row_format = @row_format; +# End of 10.3 tests SET GLOBAL innodb_default_row_format = @row_format; diff --git a/mysql-test/suite/innodb/t/default_row_format_alter.test b/mysql-test/suite/innodb/t/default_row_format_alter.test index 8f7217bcf0c..fc03ce590fa 100644 --- a/mysql-test/suite/innodb/t/default_row_format_alter.test +++ b/mysql-test/suite/innodb/t/default_row_format_alter.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/innodb_row_format.inc SET @row_format = @@GLOBAL.innodb_default_row_format; @@ -95,4 +96,17 @@ ALTER TABLE t1 DROP INDEX k1; SHOW TABLE STATUS LIKE 't1'; DROP TABLE t1; +--echo # +--echo # MDEV-24758 heap-use-after-poison in innobase_add_instant_try/rec_copy +--echo # + +CREATE TABLE t1 (pk INT PRIMARY KEY) CHARACTER SET utf8 ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +SET GLOBAL innodb_default_row_format = REDUNDANT; +ALTER TABLE t1 ADD a CHAR(8) DEFAULT ''; +DROP TABLE t1; +SET GLOBAL innodb_default_row_format = @row_format; + +--echo # End of 10.3 tests + SET GLOBAL innodb_default_row_format = @row_format; diff --git a/sql/handler.h b/sql/handler.h index fc69d9423b4..55c2f0bcd57 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2347,6 +2347,9 @@ public: /** true for online operation (LOCK=NONE) */ bool online; + /** which ALGORITHM and LOCK are supported by the storage engine */ + enum_alter_inplace_result inplace_supported; + /** Can be set by handler to describe why a given operation cannot be done in-place (HA_ALTER_INPLACE_NOT_SUPPORTED) or why it cannot be done diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index a68dcb31a4c..94003e328cc 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - Copyright (c) 2016, 2018, MariaDB Corporation + Copyright (c) 2016, 2020, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -127,10 +127,10 @@ const char* Alter_info::lock() const } -bool Alter_info::supports_algorithm(THD *thd, enum_alter_inplace_result result, +bool Alter_info::supports_algorithm(THD *thd, const Alter_inplace_info *ha_alter_info) { - switch (result) { + switch (ha_alter_info->inplace_supported) { case HA_ALTER_INPLACE_EXCLUSIVE_LOCK: case HA_ALTER_INPLACE_SHARED_LOCK: case HA_ALTER_INPLACE_NO_LOCK: @@ -171,10 +171,10 @@ bool Alter_info::supports_algorithm(THD *thd, enum_alter_inplace_result result, } -bool Alter_info::supports_lock(THD *thd, enum_alter_inplace_result result, +bool Alter_info::supports_lock(THD *thd, const Alter_inplace_info *ha_alter_info) { - switch (result) { + switch (ha_alter_info->inplace_supported) { case HA_ALTER_INPLACE_EXCLUSIVE_LOCK: // If SHARED lock and no particular algorithm was requested, use COPY. if (requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED && diff --git a/sql/sql_alter.h b/sql/sql_alter.h index 53d0c8438f8..71920b84792 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -1,5 +1,5 @@ /* Copyright (c) 2010, 2014, Oracle and/or its affiliates. - Copyright (c) 2013, 2018, MariaDB Corporation. + Copyright (c) 2013, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -204,29 +204,26 @@ public: with the specified user alter algorithm. @param thd Thread handle - @param result Operation supported for inplace alter @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data during in-place alter @retval false Supported operation @retval true Not supported value */ - bool supports_algorithm(THD *thd, enum_alter_inplace_result result, + bool supports_algorithm(THD *thd, const Alter_inplace_info *ha_alter_info); /** Check whether the given result can be supported with the specified user lock type. - @param result Operation supported for inplace alter @param ha_alter_info Structure describing changes to be done by ALTER TABLE and holding data during in-place alter @retval false Supported lock type @retval true Not supported value */ - bool supports_lock(THD *thd, enum_alter_inplace_result result, - const Alter_inplace_info *ha_alter_info); + bool supports_lock(THD *thd, const Alter_inplace_info *ha_alter_info); /** Return user requested algorithm. If user does not specify diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 64f67358194..4883fd93782 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7549,7 +7549,6 @@ static bool is_inplace_alter_impossible(TABLE *table, @param ha_alter_info Structure describing ALTER TABLE to be carried out and serving as a storage place for data used during different phases. - @param inplace_supported Enum describing the locking requirements. @param target_mdl_request Metadata request/lock on the target table name. @param alter_ctx ALTER TABLE runtime context. @@ -7574,7 +7573,6 @@ static bool mysql_inplace_alter_table(THD *thd, TABLE *table, TABLE *altered_table, Alter_inplace_info *ha_alter_info, - enum_alter_inplace_result inplace_supported, MDL_request *target_mdl_request, Alter_table_ctx *alter_ctx) { @@ -7585,6 +7583,8 @@ static bool mysql_inplace_alter_table(THD *thd, Alter_info *alter_info= ha_alter_info->alter_info; bool reopen_tables= false; bool res; + const enum_alter_inplace_result inplace_supported= + ha_alter_info->inplace_supported; DBUG_ENTER("mysql_inplace_alter_table"); @@ -10006,19 +10006,19 @@ do_continue:; if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE) ha_alter_info.online= true; // Ask storage engine whether to use copy or in-place - enum_alter_inplace_result inplace_supported= + ha_alter_info.inplace_supported= table->file->check_if_supported_inplace_alter(altered_table, &ha_alter_info); - if (alter_info->supports_algorithm(thd, inplace_supported, &ha_alter_info) || - alter_info->supports_lock(thd, inplace_supported, &ha_alter_info)) + if (alter_info->supports_algorithm(thd, &ha_alter_info) || + alter_info->supports_lock(thd, &ha_alter_info)) { thd->drop_temporary_table(altered_table, NULL, false); goto err_new_table_cleanup; } // If SHARED lock and no particular algorithm was requested, use COPY. - if (inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK && + if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK && alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED && alter_info->algorithm(thd) == Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT && @@ -10026,7 +10026,7 @@ do_continue:; Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT) use_inplace= false; - if (inplace_supported == HA_ALTER_INPLACE_NOT_SUPPORTED) + if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_NOT_SUPPORTED) use_inplace= false; if (use_inplace) @@ -10038,7 +10038,7 @@ do_continue:; */ Check_level_instant_set check_level_save(thd, CHECK_FIELD_WARN); int res= mysql_inplace_alter_table(thd, table_list, table, altered_table, - &ha_alter_info, inplace_supported, + &ha_alter_info, &target_mdl_request, &alter_ctx); my_free(const_cast(frm.str)); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 0e17488e8aa..8f12d2e3571 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -5003,6 +5003,19 @@ prepare_inplace_alter_table_dict( user_table = ctx->new_table; + switch (ha_alter_info->inplace_supported) { + default: break; + case HA_ALTER_INPLACE_INSTANT: + case HA_ALTER_INPLACE_NOCOPY_LOCK: + case HA_ALTER_INPLACE_NOCOPY_NO_LOCK: + /* If we promised ALGORITHM=NOCOPY or ALGORITHM=INSTANT, + we must retain the original ROW_FORMAT of the table. */ + flags = (user_table->flags & (DICT_TF_MASK_COMPACT + | DICT_TF_MASK_ATOMIC_BLOBS)) + | (flags & ~(DICT_TF_MASK_COMPACT + | DICT_TF_MASK_ATOMIC_BLOBS)); + } + trx_start_if_not_started_xa(ctx->prebuilt->trx, true); if (ha_alter_info->handler_flags From a35cde8cd8364edc0a23752fc5fde442c8b78a0a Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 27 Apr 2021 08:17:37 +1000 Subject: [PATCH 7/8] MDEV-25513: raise systemd LimitNOFILE limits to match server defaults Quoting MDEV reporter Daniel Lewart: Starting MariaDB with default configuration causes the following problems: "[Warning] Could not increase number of max_open_files to more than 16384 (request: 32186)" silently reduces table_open_cache_instances from 8 (default) to 4 Default Server System Variables: extra_max_connections = 1 max_connections = 151 table_open_cache = 2000 table_open_cache_instances = 8 thread_pool_size = 4 LimitNOFILE=16834 is in the following files: support-files/mariadb.service.in support-files/mariadb@.service.in Looking at sql/mysqld.cc lines 3837-3917: wanted_files= (extra_files + max_connections + extra_max_connections + tc_size * 2 * tc_instances); wanted_files+= threadpool_size; Plugging in the default values: wanted_files = (30 + 151 + 1 + 2000 * 2 * 8 + 4) = 32186 However, systemd configuration has LimitNOFILE = 16384, which is far smaller. I suggest increasing LimitNOFILE to 32768. --- support-files/mariadb.service.in | 2 +- support-files/mariadb@.service.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/support-files/mariadb.service.in b/support-files/mariadb.service.in index 245c506c117..7c885b1f6e9 100644 --- a/support-files/mariadb.service.in +++ b/support-files/mariadb.service.in @@ -142,7 +142,7 @@ TimeoutStopSec=900 ## # Number of files limit. previously [mysqld_safe] open-files-limit -LimitNOFILE=16384 +LimitNOFILE=32768 # Maximium core size. previously [mysqld_safe] core-file-size # LimitCore= diff --git a/support-files/mariadb@.service.in b/support-files/mariadb@.service.in index a487e22521b..d625ce67396 100644 --- a/support-files/mariadb@.service.in +++ b/support-files/mariadb@.service.in @@ -168,7 +168,7 @@ TimeoutStopSec=900 ## # Number of files limit. previously [mysqld_safe] open-files-limit -LimitNOFILE=16384 +LimitNOFILE=32768 # Maximium core size. previously [mysqld_safe] core-file-size # LimitCore= From 29b2f3dbb543130a7ba71635216a8d7d34cac46e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 27 Apr 2021 08:44:28 +0300 Subject: [PATCH 8/8] MDEV-24545 Sequence created by one connection remains invisible to another row_merge_is_index_usable(): Allow access to any SEQUENCE, even if it was created after the read view. SQL sequences are no-rollback tables with no history at all. --- .../sql_sequence/concurrent_create.result | 13 +++++++++++++ .../suite/sql_sequence/concurrent_create.test | 19 +++++++++++++++++++ storage/innobase/row/row0merge.cc | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/sql_sequence/concurrent_create.result b/mysql-test/suite/sql_sequence/concurrent_create.result index 7e68195f7e0..2473abef37d 100644 --- a/mysql-test/suite/sql_sequence/concurrent_create.result +++ b/mysql-test/suite/sql_sequence/concurrent_create.result @@ -31,3 +31,16 @@ connection con1; disconnect con1; connection default; DROP TABLE s1,s2; +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +START TRANSACTION WITH CONSISTENT SNAPSHOT; +connect con1,localhost,root,,test; +CREATE SEQUENCE s1 ENGINE=InnoDB; +FLUSH TABLES; +disconnect con1; +connection default; +SELECT NEXTVAL(s1); +NEXTVAL(s1) +1 +COMMIT; +DROP TABLE t1; +DROP SEQUENCE s1; diff --git a/mysql-test/suite/sql_sequence/concurrent_create.test b/mysql-test/suite/sql_sequence/concurrent_create.test index d6a57ff7d50..b27a6d3bdb9 100644 --- a/mysql-test/suite/sql_sequence/concurrent_create.test +++ b/mysql-test/suite/sql_sequence/concurrent_create.test @@ -56,3 +56,22 @@ FLUSH TABLES; --connection default DROP TABLE s1,s2; + +# +# MDEV-24545 Sequence created by one connection remains invisible to another +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +START TRANSACTION WITH CONSISTENT SNAPSHOT; + +--connect (con1,localhost,root,,test) +CREATE SEQUENCE s1 ENGINE=InnoDB; +FLUSH TABLES; +--disconnect con1 + +--connection default +SELECT NEXTVAL(s1); +COMMIT; + +# Cleanup +DROP TABLE t1; +DROP SEQUENCE s1; diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index f77eae9a76d..9e84f9db033 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -4478,7 +4478,7 @@ row_merge_is_index_usable( } return(!index->is_corrupted() - && (index->table->is_temporary() + && (index->table->is_temporary() || index->table->no_rollback() || index->trx_id == 0 || !trx->read_view.is_open() || trx->read_view.changes_visible(