From 8932517348414caa9e9a1c9ab501a5e4292c6e75 Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Wed, 19 Oct 2022 12:29:22 +0300 Subject: [PATCH] New 'RENAME TABLE ... NO LOCK CHECK' optional clause. When supplied, a 'RENAME TABLE' statement does not check for existing table write locks before operating (it does keep escalating locks as needed upon operation, as usual) Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- sql/sql_lex.h | 5 +++++ sql/sql_parse.cc | 2 +- sql/sql_rename.cc | 25 +++++++++++++++---------- sql/sql_rename.h | 2 +- sql/sql_yacc.yy | 11 ++++++++--- 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index dde2db18dc80..be3b3cab162b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3980,6 +3980,11 @@ struct LEX : public Query_tables_list { */ uint8 context_analysis_only; bool drop_if_exists; + /** + refers to optional NO LOCK CHECK clause in RENAME TABLE sql. This flag when + set to true skips the table lock validation that precedes the actual rename operation. + */ + bool no_lock_check; /** refers to optional IF EXISTS clause in REVOKE sql. This flag when set to true will report warnings in case privilege being granted is not granted to diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a27c40ee4ef0..5127e227dda3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3619,7 +3619,7 @@ int mysql_execute_command(THD *thd, bool first_level) { goto error; } - if (mysql_rename_tables(thd, first_table)) goto error; + if (mysql_rename_tables(thd, first_table, lex->no_lock_check)) goto error; break; } case SQLCOM_CHECKSUM: { diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 8d2ba01541c0..7de834c1736e 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -68,7 +68,7 @@ typedef std::set post_ddl_htons_t; static TABLE_LIST *rename_tables( THD *thd, TABLE_LIST *table_list, bool *int_commit_done, post_ddl_htons_t *post_ddl_htons, - Foreign_key_parents_invalidator *fk_invalidator); + Foreign_key_parents_invalidator *fk_invalidator, bool no_lock_check); static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list); @@ -95,7 +95,9 @@ struct table_list_equal { */ static bool check_if_owns_upgradable_mdl(THD *thd, const char *db, - const char *table_name) { + const char *table_name, bool no_lock_check) { + if (no_lock_check) + return false; // Success, skipped checks altogether if (thd->mdl_context.owns_equal_or_stronger_lock( MDL_key::TABLE, db, table_name, MDL_SHARED_NO_READ_WRITE)) return false; // Success. @@ -152,7 +154,7 @@ static void find_and_set_explicit_duration_for_schema_mdl( @return True - on failure, false - on success. */ -bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list) { +bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool no_lock_check) { TABLE_LIST *ren_table = nullptr; DBUG_TRACE; @@ -270,7 +272,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list) { auto new_name_it = new_names.find(ren_table); if (new_name_it == new_names.end()) { if (check_if_owns_upgradable_mdl(thd, ren_table->db, - ren_table->table_name)) + ren_table->table_name, + no_lock_check)) return true; } else { new_names.erase(new_name_it); @@ -325,7 +328,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list) { no other thread accesses this table. */ if ((ren_table = rename_tables(thd, table_list, &int_commit_done, - &post_ddl_htons, &fk_invalidator))) { + &post_ddl_htons, &fk_invalidator, no_lock_check))) { /* Rename didn't succeed; rename back the tables in reverse order */ TABLE_LIST *table; @@ -352,7 +355,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list) { TABLES, which this code deals with, is not the main use case anyway. */ int_commit_full_revert = !rename_tables(thd, table, &int_commit_done, - &post_ddl_htons, &fk_invalidator); + &post_ddl_htons, &fk_invalidator, no_lock_check); /* Revert the table list (for prepared statements) */ table_list = reverse_table_list(table_list); @@ -552,7 +555,8 @@ static bool do_rename(THD *thd, TABLE_LIST *ren_table, const char *new_db, const char *new_table_name, const char *new_table_alias, bool *int_commit_done, std::set *post_ddl_htons, - Foreign_key_parents_invalidator *fk_invalidator) { + Foreign_key_parents_invalidator *fk_invalidator, + bool no_lock_check) { const char *new_alias = new_table_name; const char *old_alias = ren_table->table_name; @@ -710,7 +714,8 @@ static bool do_rename(THD *thd, TABLE_LIST *ren_table, const char *new_db, if (mdl_request->key.mdl_namespace() != MDL_key::TABLE) continue; if (check_if_owns_upgradable_mdl(thd, mdl_request->key.db_name(), - mdl_request->key.name())) { + mdl_request->key.name(), + no_lock_check)) { // See explanation for clearing foreign key invalidator below. fk_invalidator->clear(); return true; @@ -924,7 +929,7 @@ static bool do_rename(THD *thd, TABLE_LIST *ren_table, const char *new_db, static TABLE_LIST *rename_tables( THD *thd, TABLE_LIST *table_list, bool *int_commit_done, post_ddl_htons_t *post_ddl_htons, - Foreign_key_parents_invalidator *fk_invalidator) + Foreign_key_parents_invalidator *fk_invalidator, bool no_lock_check) { TABLE_LIST *ren_table, *new_table; @@ -935,7 +940,7 @@ static TABLE_LIST *rename_tables( new_table = ren_table->next_local; if (do_rename(thd, ren_table, new_table->db, new_table->table_name, new_table->alias, int_commit_done, post_ddl_htons, - fk_invalidator)) + fk_invalidator, no_lock_check)) return ren_table; } return nullptr; diff --git a/sql/sql_rename.h b/sql/sql_rename.h index 7a04386b6bb6..5e22b3f0ca5e 100644 --- a/sql/sql_rename.h +++ b/sql/sql_rename.h @@ -26,6 +26,6 @@ class THD; struct TABLE_LIST; -bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); +bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool no_lock_check); #endif /* SQL_RENAME_INCLUDED */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b7f06248a36e..b98318bc97ef 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1479,6 +1479,7 @@ void warn_about_deprecated_binary(THD *thd) lock_option udf_type if_exists opt_no_write_to_binlog + opt_no_lock_check all_or_any opt_distinct fulltext_options union_option transaction_access_mode_types @@ -9654,13 +9655,17 @@ opt_no_write_to_binlog: | LOCAL_SYM { $$= 1; } ; +opt_no_lock_check: + /* empty */ { $$= 0; } + | NO_SYM LOCK_SYM CHECK_SYM { $$= 1; } + ; + rename: - RENAME table_or_tables + RENAME table_or_tables table_to_table_list opt_no_lock_check { Lex->sql_command= SQLCOM_RENAME_TABLE; + Lex->no_lock_check = $4; } - table_to_table_list - {} | RENAME USER rename_list { Lex->sql_command = SQLCOM_RENAME_USER;