Commit a5bcec72 authored by Jan Lindström's avatar Jan Lindström

MDEV-24865 : Server crashes when truncate mysql user table

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.
parent d0defd1e
...@@ -32,6 +32,17 @@ SELECT AUTO_INCREMENT = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME IN ('t ...@@ -32,6 +32,17 @@ SELECT AUTO_INCREMENT = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME IN ('t
AUTO_INCREMENT = 1 AUTO_INCREMENT = 1
1 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 t1;
DROP TABLE t2; DROP TABLE t2;
DROP TABLE t3; DROP TABLE t3;
......
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
# #
--source include/galera_cluster.inc --source include/galera_cluster.inc
--source include/have_innodb.inc --source include/have_perfschema.inc
# #
# Simple case # Simple case
# #
...@@ -54,6 +53,23 @@ TRUNCATE TABLE t4; ...@@ -54,6 +53,23 @@ TRUNCATE TABLE t4;
--connection node_2 --connection node_2
SELECT AUTO_INCREMENT = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME IN ('t3', 't4'); 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 t1;
DROP TABLE t2; DROP TABLE t2;
DROP TABLE t3; DROP TABLE t3;
......
...@@ -416,20 +416,23 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) ...@@ -416,20 +416,23 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
bool hton_can_recreate; bool hton_can_recreate;
#ifdef WITH_WSREP #ifdef WITH_WSREP
if (WSREP(thd)) if (WSREP(thd) && wsrep_thd_is_local(thd))
{ {
wsrep::key_array keys; wsrep::key_array keys;
wsrep_append_fk_parent_table(thd, table_ref, &keys); /* Do not start TOI if table is not found */
if (keys.empty()) 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); WSREP_TO_ISOLATION_BEGIN_IF(table_ref->db.str, table_ref->table_name.str, NULL)
} {
} else { DBUG_RETURN(TRUE);
WSREP_TO_ISOLATION_BEGIN_FK_TABLES(NULL, NULL, table_ref, &keys) }
{ } else {
DBUG_RETURN(TRUE); WSREP_TO_ISOLATION_BEGIN_FK_TABLES(NULL, NULL, table_ref, &keys)
{
DBUG_RETURN(TRUE);
}
} }
} }
} }
......
...@@ -1184,10 +1184,17 @@ void wsrep_keys_free(wsrep_key_arr_t* key_arr) ...@@ -1184,10 +1184,17 @@ void wsrep_keys_free(wsrep_key_arr_t* key_arr)
key_arr->keys_len= 0; 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) 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; TABLE_LIST *table;
thd->release_transactional_locks(); thd->release_transactional_locks();
...@@ -1198,6 +1205,8 @@ wsrep_append_fk_parent_table(THD* thd, TABLE_LIST* tables, wsrep::key_array* key ...@@ -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)) 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()); 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) 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 ...@@ -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 the table and release MDL locks */
close_thread_tables(thd); close_thread_tables(thd);
thd->mdl_context.rollback_to_savepoint(mdl_savepoint); thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
for (table= tables; table; table= table->next_local) for (table= tables; table; table= table->next_local)
{ {
table->table= NULL; table->table= NULL;
table->next_global= NULL;
table->mdl_request.ticket= 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, ...@@ -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); 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) if (wsrep_can_run_in_toi(thd, db, table, table_list) == false)
{ {
WSREP_DEBUG("No TOI for %s", WSREP_QUERY(thd)); WSREP_DEBUG("No TOI for %s", WSREP_QUERY(thd));
...@@ -2055,22 +2068,20 @@ static void wsrep_TOI_end(THD *thd) { ...@@ -2055,22 +2068,20 @@ static void wsrep_TOI_end(THD *thd) {
wsrep_to_isolation--; wsrep_to_isolation--;
wsrep::client_state& client_state(thd->wsrep_cs()); wsrep::client_state& client_state(thd->wsrep_cs());
DBUG_ASSERT(wsrep_thd_is_local_toi(thd)); 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()); WSREP_DEBUG("TO END: %lld: %s",
int ret= client_state.leave_toi_local(wsrep::mutable_buffer()); client_state.toi_meta().seqno().get(), WSREP_QUERY(thd));
if (!ret) }
{ else
WSREP_DEBUG("TO END: %lld", client_state.toi_meta().seqno().get()); {
} WSREP_WARN("TO isolation end failed for: %d, sql: %s",
else ret, WSREP_QUERY(thd));
{
WSREP_WARN("TO isolation end failed for: %d, schema: %s, sql: %s",
ret, (thd->db.str ? thd->db.str : "(null)"), WSREP_QUERY(thd));
}
} }
} }
......
...@@ -212,7 +212,7 @@ wsrep_sync_wait_upto (THD* thd, wsrep_gtid_t* upto, int timeout); ...@@ -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 void wsrep_last_committed_id (wsrep_gtid_t* gtid);
extern int wsrep_check_opts(); extern int wsrep_check_opts();
extern void wsrep_prepend_PATH (const char* path); 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 */ /* Other global variables */
extern wsrep_seqno_t wsrep_locked_seqno; extern wsrep_seqno_t wsrep_locked_seqno;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment