summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lindström <jan.lindstrom@mariadb.com>2021-02-16 08:46:14 +0200
committerJan Lindström <jan.lindstrom@mariadb.com>2021-02-16 08:46:14 +0200
commita5bcec727b096f634e43f9031440cc1dc9e302c2 (patch)
treec1005cdf624719b0e97e318b0d11cd5ec81bfc52
parentd0defd1ea2af80a360332fd8c1e60a34e2289213 (diff)
downloadmariadb-git-bb-10.4-MDEV-24865.tar.gz
MDEV-24865 : Server crashes when truncate mysql user tablebb-10.4-MDEV-24865
For truncate we try to find out possible foreign key tables using open_tables. However, table_list was not cleaned up properly and there was no error handling. Fixed by cleaning table_list and adding proper error handling.
-rw-r--r--mysql-test/suite/galera/r/galera_truncate.result11
-rw-r--r--mysql-test/suite/galera/t/galera_truncate.test20
-rw-r--r--sql/sql_truncate.cc23
-rw-r--r--sql/wsrep_mysqld.cc45
-rw-r--r--sql/wsrep_mysqld.h2
5 files changed, 71 insertions, 30 deletions
diff --git a/mysql-test/suite/galera/r/galera_truncate.result b/mysql-test/suite/galera/r/galera_truncate.result
index c649d9bbaf9..c9a4bc854f8 100644
--- a/mysql-test/suite/galera/r/galera_truncate.result
+++ b/mysql-test/suite/galera/r/galera_truncate.result
@@ -32,6 +32,17 @@ SELECT AUTO_INCREMENT = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME IN ('t
AUTO_INCREMENT = 1
1
1
+connection node_1;
+TRUNCATE TABLE mysql.user;
+ERROR 42S02: Table 'mysql.user' doesn't exist
+TRUNCATE TABLE performance_schema.threads;
+ERROR HY000: Invalid performance_schema usage
+TRUNCATE TABLE information_schema.tables;
+ERROR 42000: Access denied for user 'root'@'localhost' to database 'information_schema'
+TRUNCATE TABLE mysql.innodb_index_stats;
+TRUNCATE TABLE foo.bar;
+ERROR 42S02: Table 'foo.bar' doesn't exist
+TRUNCATE TABLE t1;
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
diff --git a/mysql-test/suite/galera/t/galera_truncate.test b/mysql-test/suite/galera/t/galera_truncate.test
index 3c3ee56a23f..c3dd02017bb 100644
--- a/mysql-test/suite/galera/t/galera_truncate.test
+++ b/mysql-test/suite/galera/t/galera_truncate.test
@@ -3,8 +3,7 @@
#
--source include/galera_cluster.inc
---source include/have_innodb.inc
-
+--source include/have_perfschema.inc
#
# Simple case
#
@@ -54,6 +53,23 @@ TRUNCATE TABLE t4;
--connection node_2
SELECT AUTO_INCREMENT = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME IN ('t3', 't4');
+
+#
+# MDEV-24865 : Server crashes when truncate mysql user table
+#
+--connection node_1
+
+--error ER_NO_SUCH_TABLE
+TRUNCATE TABLE mysql.user;
+--error ER_WRONG_PERFSCHEMA_USAGE
+TRUNCATE TABLE performance_schema.threads;
+--error ER_DBACCESS_DENIED_ERROR
+TRUNCATE TABLE information_schema.tables;
+TRUNCATE TABLE mysql.innodb_index_stats;
+--error ER_NO_SUCH_TABLE
+TRUNCATE TABLE foo.bar;
+TRUNCATE TABLE t1;
+
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index c3d347307a2..e7ecdda958e 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -416,20 +416,23 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
bool hton_can_recreate;
#ifdef WITH_WSREP
- if (WSREP(thd))
+ if (WSREP(thd) && wsrep_thd_is_local(thd))
{
wsrep::key_array keys;
- wsrep_append_fk_parent_table(thd, table_ref, &keys);
- if (keys.empty())
+ /* Do not start TOI if table is not found */
+ if (!wsrep_append_fk_parent_table(thd, table_ref, &keys))
{
- WSREP_TO_ISOLATION_BEGIN_IF(table_ref->db.str, table_ref->table_name.str, NULL)
+ if (keys.empty())
{
- DBUG_RETURN(TRUE);
- }
- } else {
- WSREP_TO_ISOLATION_BEGIN_FK_TABLES(NULL, NULL, table_ref, &keys)
- {
- DBUG_RETURN(TRUE);
+ WSREP_TO_ISOLATION_BEGIN_IF(table_ref->db.str, table_ref->table_name.str, NULL)
+ {
+ DBUG_RETURN(TRUE);
+ }
+ } else {
+ WSREP_TO_ISOLATION_BEGIN_FK_TABLES(NULL, NULL, table_ref, &keys)
+ {
+ DBUG_RETURN(TRUE);
+ }
}
}
}
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index c0f48cca9cd..5fbed9666c4 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -1184,10 +1184,17 @@ void wsrep_keys_free(wsrep_key_arr_t* key_arr)
key_arr->keys_len= 0;
}
-void
+/*!
+ * @param thd thread
+ * @param tables list of tables
+ * @param keys prepared keys
+
+ * @return true if parent table append was successfull, otherwise false.
+*/
+bool
wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* tables, wsrep::key_array* keys)
{
- if (!WSREP(thd) || !WSREP_CLIENT(thd)) return;
+ bool fail= false;
TABLE_LIST *table;
thd->release_transactional_locks();
@@ -1198,6 +1205,8 @@ wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* tables, wsrep::key_array* key
open_tables(thd, &tables, &counter, MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
{
WSREP_DEBUG("unable to open table for FK checks for %s", thd->query());
+ fail= true;
+ goto exit;
}
for (table= tables; table; table= table->next_local)
@@ -1219,14 +1228,18 @@ wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* tables, wsrep::key_array* key
}
}
+exit:
/* close the table and release MDL locks */
close_thread_tables(thd);
thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
for (table= tables; table; table= table->next_local)
{
table->table= NULL;
+ table->next_global= NULL;
table->mdl_request.ticket= NULL;
}
+
+ return fail;
}
/*!
@@ -1965,7 +1978,7 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table,
{
DBUG_ASSERT(thd->variables.wsrep_OSU_method == WSREP_OSU_TOI);
- WSREP_DEBUG("TOI Begin");
+ WSREP_DEBUG("TOI Begin for %s", WSREP_QUERY(thd));
if (wsrep_can_run_in_toi(thd, db, table, table_list) == false)
{
WSREP_DEBUG("No TOI for %s", WSREP_QUERY(thd));
@@ -2055,22 +2068,20 @@ static void wsrep_TOI_end(THD *thd) {
wsrep_to_isolation--;
wsrep::client_state& client_state(thd->wsrep_cs());
DBUG_ASSERT(wsrep_thd_is_local_toi(thd));
- WSREP_DEBUG("TO END: %lld: %s", client_state.toi_meta().seqno().get(),
- WSREP_QUERY(thd));
- if (wsrep_thd_is_local_toi(thd))
+ wsrep_set_SE_checkpoint(client_state.toi_meta().gtid());
+
+ int ret= client_state.leave_toi_local(wsrep::mutable_buffer());
+
+ if (!ret)
{
- wsrep_set_SE_checkpoint(client_state.toi_meta().gtid());
- int ret= client_state.leave_toi_local(wsrep::mutable_buffer());
- if (!ret)
- {
- WSREP_DEBUG("TO END: %lld", client_state.toi_meta().seqno().get());
- }
- else
- {
- WSREP_WARN("TO isolation end failed for: %d, schema: %s, sql: %s",
- ret, (thd->db.str ? thd->db.str : "(null)"), WSREP_QUERY(thd));
- }
+ WSREP_DEBUG("TO END: %lld: %s",
+ client_state.toi_meta().seqno().get(), WSREP_QUERY(thd));
+ }
+ else
+ {
+ WSREP_WARN("TO isolation end failed for: %d, sql: %s",
+ ret, WSREP_QUERY(thd));
}
}
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index 29b1c4cf1f4..2ec3943b5c2 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -212,7 +212,7 @@ wsrep_sync_wait_upto (THD* thd, wsrep_gtid_t* upto, int timeout);
extern void wsrep_last_committed_id (wsrep_gtid_t* gtid);
extern int wsrep_check_opts();
extern void wsrep_prepend_PATH (const char* path);
-void wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* table, wsrep::key_array* keys);
+extern bool wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* table, wsrep::key_array* keys);
/* Other global variables */
extern wsrep_seqno_t wsrep_locked_seqno;