
revision-id: 20f347974f6a9b4e2c65a5ca79aefb8e118ba6cd (mariadb-10.1.33-33-g20f3479) parent(s): 3627dd7f6a1cf5bd7151ff23290d64cb6dffea90 committer: Alexey Botchkov timestamp: 2018-06-11 14:58:46 +0400 message: MDEV-15890 Strange error message if you try to FLUSH TABLES <view> after LOCK TABLES <view>. The reload_acl_and_cache() now looks into the VIEW definition to check the involved tables if the locked_tables_mode. --- mysql-test/r/flush.result | 12 ++++++++++++ mysql-test/t/flush.test | 15 +++++++++++++++ sql/sql_base.cc | 38 +++++++++++++++++++++++++------------- sql/sql_base.h | 2 +- sql/sql_reload.cc | 36 ++++++++++++++++++++++++++++++++++-- sql/sql_table.cc | 2 +- sql/sql_trigger.cc | 2 +- sql/sql_truncate.cc | 2 +- 8 files changed, 90 insertions(+), 19 deletions(-) diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result index b643510..8991032 100644 --- a/mysql-test/r/flush.result +++ b/mysql-test/r/flush.result @@ -496,3 +496,15 @@ flush relay logs,relay logs; ERROR HY000: Incorrect usage of FLUSH and RELAY LOGS flush slave,slave; ERROR HY000: Incorrect usage of FLUSH and SLAVE +# +# MDEV-15890 Strange error message if you try to +# FLUSH TABLES <view> after LOCK TABLES <view>. +# +CREATE TABLE t1 (qty INT, price INT); +CREATE VIEW v1 AS SELECT qty, price, qty*price AS value FROM t1; +LOCK TABLES v1 READ; +FLUSH TABLES v1; +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +UNLOCK TABLES; +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test index a1df935..4db7975 100644 --- a/mysql-test/t/flush.test +++ b/mysql-test/t/flush.test @@ -709,3 +709,18 @@ DROP TABLE t1; flush relay logs,relay logs; --error ER_WRONG_USAGE flush slave,slave; + +--echo # +--echo # MDEV-15890 Strange error message if you try to +--echo # FLUSH TABLES <view> after LOCK TABLES <view>. +--echo # + +CREATE TABLE t1 (qty INT, price INT); +CREATE VIEW v1 AS SELECT qty, price, qty*price AS value FROM t1; +LOCK TABLES v1 READ; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +FLUSH TABLES v1; +UNLOCK TABLES; +DROP VIEW v1; +DROP TABLE t1; + diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d671bb4..8561622 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -522,9 +522,10 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, for (TABLE_LIST *table_list= tables_to_reopen; table_list; table_list= table_list->next_global) { + int err; /* A check that the table was locked for write is done by the caller. */ TABLE *table= find_table_for_mdl_upgrade(thd, table_list->db, - table_list->table_name, TRUE); + table_list->table_name, &err); /* May return NULL if this table has already been closed via an alias. */ if (! table) @@ -2666,8 +2667,9 @@ TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name) @param thd Thread context @param db Database name. @param table_name Name of table. - @param no_error Don't emit error if no suitable TABLE - instance were found. + @param p_error In the case of an error (when the function returns NULL) + the error number is stored there. + If the p_error is NULL, function launches the error itself. @note This function checks if the connection holds a global IX metadata lock. If no such lock is found, it is not safe to @@ -2680,15 +2682,15 @@ TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name) */ TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db, - const char *table_name, bool no_error) + const char *table_name, int *p_error) { TABLE *tab= find_locked_table(thd->open_tables, db, table_name); + int error; if (!tab) { - if (!no_error) - my_error(ER_TABLE_NOT_LOCKED, MYF(0), table_name); - return NULL; + error= ER_TABLE_NOT_LOCKED; + goto err_exit; } /* @@ -2700,9 +2702,8 @@ TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db, if (!thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE)) { - if (!no_error) - my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name); - return NULL; + error= ER_TABLE_NOT_LOCKED_FOR_WRITE; + goto err_exit; } while (tab->mdl_ticket != NULL && @@ -2710,10 +2711,21 @@ TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db, (tab= find_locked_table(tab->next, db, table_name))) continue; - if (!tab && !no_error) - my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name); + if (!tab) + { + error= ER_TABLE_NOT_LOCKED_FOR_WRITE; + goto err_exit; + } return tab; + +err_exit: + if (p_error) + *p_error= error; + else + my_error(error, MYF(0), table_name); + + return NULL; } @@ -4446,7 +4458,7 @@ open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start, Note that find_table_for_mdl_upgrade() will report an error if no suitable ticket is found. */ - if (!find_table_for_mdl_upgrade(thd, table->db, table->table_name, false)) + if (!find_table_for_mdl_upgrade(thd, table->db, table->table_name, NULL)) return TRUE; } diff --git a/sql/sql_base.h b/sql/sql_base.h index 7415418..e9dd0f5 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -329,7 +329,7 @@ static inline bool tdc_open_view(THD *thd, TABLE_LIST *table_list, TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db, const char *table_name, - bool no_error); + int *p_error); void mark_tmp_table_for_reuse(TABLE *table); int update_virtual_fields(THD *thd, TABLE *table, diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index 73dd967..a0bee37 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -30,6 +30,7 @@ #include "sql_show.h" #include "debug_sync.h" #include "des_key_file.h" +#include "sql_view.h" static void disable_checkpoints(THD *thd); @@ -288,9 +289,40 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, */ if (tables) { + int err; for (TABLE_LIST *t= tables; t; t= t->next_local) - if (!find_table_for_mdl_upgrade(thd, t->db, t->table_name, false)) - return 1; + if (!find_table_for_mdl_upgrade(thd, t->db, t->table_name, &err)) + { + TABLE_SHARE *share; + TABLE *table; + const char *key; + uint key_length; + int res; + + key_length= get_table_def_key(t, &key); + share= tdc_acquire_share(thd, t->db, t->table_name, + key, key_length, + t->mdl_request.key.tc_hash_value(), + GTS_VIEW | GTS_TABLE, &table); + if (!share) + return 1; + + if (!share->is_view) + { + my_error(err, MYF(0), t->table_name); + res= 1; + } + else + { + res= mysql_make_view(thd, share, t, false); + t->next_local= t->next_global; + } + + tdc_release_share(share); + + if (res) + return 1; + } } else { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a68f9e6..d49985b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2070,7 +2070,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, in its elements. */ table->table= find_table_for_mdl_upgrade(thd, table->db, - table->table_name, false); + table->table_name, NULL); if (!table->table) DBUG_RETURN(true); table->mdl_request.ticket= table->table->mdl_ticket; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index bbcc757..515a40da 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -531,7 +531,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) /* Under LOCK TABLES we must only accept write locked tables. */ if (!(tables->table= find_table_for_mdl_upgrade(thd, tables->db, tables->table_name, - FALSE))) + NULL))) goto end; } else diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 8a70e6f..5b313fc 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -302,7 +302,7 @@ bool Sql_cmd_truncate_table::lock_table(THD *thd, TABLE_LIST *table_ref, if (thd->locked_tables_mode) { if (!(table= find_table_for_mdl_upgrade(thd, table_ref->db, - table_ref->table_name, FALSE))) + table_ref->table_name, NULL))) DBUG_RETURN(TRUE); *hton_can_recreate= ha_check_storage_engine_flag(table->s->db_type(),