From d8fa71a089aa5cbe569e7f8b6fa67326a9ecab2b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 19 May 2021 22:26:02 +0200 Subject: MDEV-25730: maria.repair test fails with valgrind cherry-pick commit: 1fff2398ef3dda1a7e8404f18e4e165823bd4e0a MDEV-22530 post push fixes from 10.6. Followup. If the KILL happens - report it as a failure, don't eat it up silently. Note that this has to be done after `table_name` is populated, so that the error message could show it. --- sql/sql_admin.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 21afa1154f6..3fa00b81f2e 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -499,8 +499,6 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, DBUG_PRINT("admin", ("table: '%s'.'%s'", table->db, table->table_name)); DEBUG_SYNC(thd, "admin_command_kill_before_modify"); - if (thd->is_killed()) - break; strxmov(table_name, db, ".", table->table_name, NullS); thd->open_options|= extra_open_options; table->lock_type= lock_type; @@ -515,6 +513,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, : lock_type >= TL_WRITE_ALLOW_WRITE ? MDL_SHARED_WRITE : MDL_SHARED_READ); + if (thd->check_killed()) + { + fatal_error= true; + result_code= HA_ADMIN_FAILED; + goto send_result; + } + /* open only one table from local list of command */ while (1) { -- cgit v1.2.1 From e212415690c78b1decc8d7b7bfdb715426c4e49f Mon Sep 17 00:00:00 2001 From: sjaakola Date: Mon, 24 May 2021 18:58:57 +0300 Subject: MDEV-25551 applying crash with tables without PK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The underlying problem with MDEV-25551 turned out to be that transactions having changes for tables with no primary key, were not safe to apply in parallel. This is due to excessive locking in innodb side, and even non related row modifications could end up in lock conflict during applying. The fix for MDEV-25551 has disabled parallel applying for tables with no PK. This fix depends on change for wsrep-lib, where a separate PR allows application to modify transaction flags in wsrep-lib. This commit has also separate mtr test for verifying that transactions modifying a table with no primary key, will not apply in parallel. This test is a modified version of initial test created by Gabor Orosz, the reporterr of MDEV-25551. Another mtr test was added in galera_sr suite, for testing if modifying tables with no primary key would causes issues for streaming replication use cases. Reviewed-by: Jan Lindström --- sql/handler.cc | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index ac5b43249db..99ec0f01320 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6808,8 +6808,21 @@ int handler::ha_update_row(const uchar *old_data, const uchar *new_data) rows_changed++; error= binlog_log_row(table, old_data, new_data, log_func); #ifdef WITH_WSREP + THD *thd= ha_thd(); + bool is_wsrep= WSREP(thd); + /* for SR, the followin wsrep_after_row() may replicate a fragment, so we have to + declare potential PA unsafe before that*/ + if (table->s->primary_key == MAX_KEY && + is_wsrep && wsrep_thd_is_local(thd)) + { + WSREP_DEBUG("marking trx as PA unsafe pk %d", table->s->primary_key); + if (thd->wsrep_cs().mark_transaction_pa_unsafe()) + { + WSREP_DEBUG("session does not have active transaction, can not mark as PA unsafe"); + } + } if (table_share->tmp_table == NO_TMP_TABLE && - WSREP(ha_thd()) && (error= wsrep_after_row(ha_thd()))) + is_wsrep && (error= wsrep_after_row(thd))) { return error; } @@ -6870,8 +6883,21 @@ int handler::ha_delete_row(const uchar *buf) rows_changed++; error= binlog_log_row(table, buf, 0, log_func); #ifdef WITH_WSREP + THD *thd= ha_thd(); + bool is_wsrep= WSREP(thd); + /* for SR, the followin wsrep_after_row() may replicate a fragment, so we have to + declare potential PA unsafe before that*/ + if (table->s->primary_key == MAX_KEY && + is_wsrep && wsrep_thd_is_local(thd)) + { + WSREP_DEBUG("marking trx as PA unsafe pk %d", table->s->primary_key); + if (thd->wsrep_cs().mark_transaction_pa_unsafe()) + { + WSREP_DEBUG("session does not have active transaction, can not mark as PA unsafe"); + } + } if (table_share->tmp_table == NO_TMP_TABLE && - WSREP(ha_thd()) && (error= wsrep_after_row(ha_thd()))) + is_wsrep && (error= wsrep_after_row(thd))) { return error; } -- cgit v1.2.1 From aa284e02374c2abdb9ae660c232c076276d2ce98 Mon Sep 17 00:00:00 2001 From: Monty Date: Wed, 26 May 2021 14:35:23 +0300 Subject: MDEV-17749 Kill during LOCK TABLE ; ALTER TABLE causes assert The problem was that when LOCK TABLES where unwinded as part of a killed connection, unlink_all_closed_tables() did not like that there was uncommited transactions. Fixed by doing a rollback of any open transaction in this particular case. --- sql/sql_base.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f793556cf62..e80a78ff802 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2469,7 +2469,17 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count) /* If no tables left, do an automatic UNLOCK TABLES */ if (thd->lock && thd->lock->table_count == 0) + { + /* + We have to rollback any open transactions here. + This is required in the case where the server has been killed + but some transations are still open (as part of locked tables). + If we don't do this, we will get an assert in unlock_locked_tables(). + */ + ha_rollback_trans(thd, FALSE); + ha_rollback_trans(thd, TRUE); unlock_locked_tables(thd); + } } -- cgit v1.2.1 From ab87fc6c7ad4ce261a833330e939facc4358612a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 27 May 2021 09:31:19 +0300 Subject: Cleanup: Remove handler::update_table_comment() The only call of the virtual member function handler::update_table_comment() was removed in commit 82d28fada7dc928564aefac802400c6684c11917 (MySQL 5.5.53) but the implementation was not removed. The only non-trivial implementation was for InnoDB. The information is now returned via handler::get_foreign_key_create_info() and ha_statistics::delete_length. --- sql/ha_partition.cc | 21 +-------------------- sql/ha_partition.h | 7 +------ sql/handler.h | 4 +--- 3 files changed, 3 insertions(+), 29 deletions(-) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 523e76e511e..ad020acf5c4 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2005, 2019, Oracle and/or its affiliates. - Copyright (c) 2009, 2019, MariaDB + Copyright (c) 2009, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2244,25 +2244,6 @@ void ha_partition::change_table_ptr(TABLE *table_arg, TABLE_SHARE *share) } } -/* - Change comments specific to handler - - SYNOPSIS - update_table_comment() - comment Original comment - - RETURN VALUE - new comment - - DESCRIPTION - No comment changes so far -*/ - -char *ha_partition::update_table_comment(const char *comment) -{ - return (char*) comment; /* Nothing to change */ -} - /** Handle delete and rename table diff --git a/sql/ha_partition.h b/sql/ha_partition.h index a48aa639237..34174089bf6 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -3,7 +3,7 @@ /* Copyright (c) 2005, 2012, Oracle and/or its affiliates. - Copyright (c) 2009, 2013, Monty Program Ab & SkySQL Ab. + Copyright (c) 2009, 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 @@ -314,10 +314,6 @@ public: Meta data routines to CREATE, DROP, RENAME table and often used at ALTER TABLE (update_create_info used from ALTER TABLE and SHOW ..). - update_table_comment is used in SHOW TABLE commands to provide a - chance for the handler to add any interesting comments to the table - comments not provided by the users comment. - create_partitioning_metadata is called before opening a new handler object with openfrm to call create. It is used to create any local handler object needed in opening the object in openfrm @@ -330,7 +326,6 @@ public: virtual int create_partitioning_metadata(const char *name, const char *old_name, int action_flag); virtual void update_create_info(HA_CREATE_INFO *create_info); - virtual char *update_table_comment(const char *comment); virtual int change_partitions(HA_CREATE_INFO *create_info, const char *path, ulonglong * const copied, diff --git a/sql/handler.h b/sql/handler.h index f618c1d6469..b3617d7a47a 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2,7 +2,7 @@ #define HANDLER_INCLUDED /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. - Copyright (c) 2009, 2019, MariaDB + Copyright (c) 2009, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -3363,8 +3363,6 @@ public: /* end of the list of admin commands */ virtual int indexes_are_disabled(void) {return 0;} - virtual char *update_table_comment(const char * comment) - { return (char*) comment;} virtual void append_create_info(String *packet) {} /** If index == MAX_KEY then a check for table is made and if index < -- cgit v1.2.1 From 91bde0fb67e9da6cb9ee1464ad684c0f681e47c9 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Sun, 30 May 2021 17:31:55 +0700 Subject: MDEV-25576: The statement EXPLAIN running as regular statement and as prepared statement produces different results for UPDATE with subquery Both EXPLAIN and EXPLAIN EXTENDED statements produce different results set in case it is run in normal way and in PS mode for the statements UPDATE/DELETE with subquery. The use case below reproduces the issue: MariaDB [test]> CREATE TABLE t1 (c1 INT KEY) ENGINE=MyISAM; Query OK, 0 rows affected (0,128 sec) MariaDB [test]> CREATE TABLE t2 (c2 INT) ENGINE=MyISAM; Query OK, 0 rows affected (0,023 sec) MariaDB [test]> CREATE TABLE t3 (c3 INT) ENGINE=MyISAM; Query OK, 0 rows affected (0,021 sec) MariaDB [test]> EXPLAIN EXTENDED UPDATE t3 SET c3 = -> ( SELECT COUNT(d1.c1) FROM ( SELECT a11.c1 FROM t1 AS a11 -> STRAIGHT_JOIN t2 AS a21 ON a21.c2 = a11.c1 JOIN t1 AS a12 -> ON a12.c1 = a11.c1 ) d1 ); +------+-------------+-------+------+---------------+------+---------+------+------+----------+--------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +------+-------------+-------+------+---------------+------+---------+------+------+----------+--------------------------------+ | 1 | PRIMARY | t3 | ALL | NULL | NULL | NULL | NULL | 0 | 100.00 | | | 2 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables +------+-------------+-------+------+---------------+------+---------+------+------+----------+--------------------------------+ 2 rows in set (0,002 sec) MariaDB [test]> PREPARE stmt FROM -> EXPLAIN EXTENDED UPDATE t3 SET c3 = -> ( SELECT COUNT(d1.c1) FROM ( SELECT a11.c1 FROM t1 AS a11 -> STRAIGHT_JOIN t2 AS a21 ON a21.c2 = a11.c1 JOIN t1 AS a12 -> ON a12.c1 = a11.c1 ) d1 ); Query OK, 0 rows affected (0,000 sec) Statement prepared MariaDB [test]> EXECUTE stmt; +------+-------------+-------+------+---------------+------+---------+------+------+----------+--------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +------+-------------+-------+------+---------------+------+---------+------+------+----------+--------------------------------+ | 1 | PRIMARY | t3 | ALL | NULL | NULL | NULL | NULL | 0 | 100.00 | | | 2 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | no matching row in const table | +------+-------------+-------+------+---------------+------+---------+------+------+----------+--------------------------------+ 2 rows in set (0,000 sec) The reason by that different result sets are produced is that on execution of the statement 'EXECUTE stmt' the flag SELECT_DESCRIBE not set in the data member SELECT_LEX::options for instances of SELECT_LEX that correspond to subqueries used in the UPDTAE/DELETE statements. Initially, these flags were set on parsing the statement PREPARE stmt FROM "EXPLAIN EXTENDED UPDATE t3 SET ..." but latter they were reset before starting real execution of the parsed query during handling the statement 'EXECUTE stmt'; So, to fix the issue the functions mysql_update()/mysql_delete() have been modified to set the flag SELECT_DESCRIBE forcibly in the data member SELECT_LEX::options for the primary SELECT_LEX of the UPDATE/DELETE statement. --- sql/sql_base.cc | 17 +++++++++++++++++ sql/sql_base.h | 2 ++ sql/sql_delete.cc | 2 ++ sql/sql_update.cc | 2 ++ 4 files changed, 23 insertions(+) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c9a34221544..11f4cb9890b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8794,6 +8794,23 @@ int dynamic_column_error_message(enum_dyncol_func_result rc) return rc; } + +/** + Turn on the SELECT_DESCRIBE flag for the primary SELECT_LEX of the statement + being processed in case the statement is EXPLAIN UPDATE/DELETE. + + @param lex current LEX +*/ + +void promote_select_describe_flag_if_needed(LEX *lex) +{ + if (lex->describe) + { + lex->select_lex.options |= SELECT_DESCRIBE; + } +} + + /** @} (end of group Data_Dictionary) */ diff --git a/sql/sql_base.h b/sql/sql_base.h index b67341bcbda..5674e8378c5 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -516,6 +516,8 @@ bool extend_table_list(THD *thd, TABLE_LIST *tables, Prelocking_strategy *prelocking_strategy, bool has_prelocking_list); +void promote_select_describe_flag_if_needed(LEX *lex); + /** A context of open_tables() function, used to recover from a failed open_table() or open_routine() attempt. diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index e2bf2d727b1..a26e15431a6 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -274,6 +274,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, query_plan.table= table; query_plan.updating_a_view= MY_TEST(table_list->view); + promote_select_describe_flag_if_needed(thd->lex); + if (mysql_prepare_delete(thd, table_list, select_lex->with_wild, select_lex->item_list, &conds)) DBUG_RETURN(TRUE); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index ec27ccda778..b7ef7c2a0db 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -342,6 +342,8 @@ int mysql_update(THD *thd, want_privilege= (table_list->view ? UPDATE_ACL : table_list->grant.want_privilege); #endif + promote_select_describe_flag_if_needed(thd->lex); + if (mysql_prepare_update(thd, table_list, &conds, order_num, order)) DBUG_RETURN(1); -- cgit v1.2.1