diff options
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 160 |
1 files changed, 103 insertions, 57 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cae5b4a3f7d..52474116fa6 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -411,9 +411,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) @@ -1461,6 +1462,66 @@ open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx, /** + Check if the given table is actually a VIEW that was LOCK-ed + + @param thd Thread context. + @param t Table to check. + + @retval TRUE The 't'-table is a locked view + needed to remedy problem before retrying again. + @retval FALSE 't' was not locked, not a VIEW or an error happened. +*/ +bool is_locked_view(THD *thd, TABLE_LIST *t) +{ + DBUG_ENTER("check_locked_view"); + /* + Is this table a view and not a base table? + (it is work around to allow to open view with locked tables, + real fix will be made after definition cache will be made) + + Since opening of view which was not explicitly locked by LOCK + TABLES breaks metadata locking protocol (potentially can lead + to deadlocks) it should be disallowed. + */ + if (thd->mdl_context.is_lock_owner(MDL_key::TABLE, + t->db, t->table_name, + MDL_SHARED)) + { + char path[FN_REFLEN + 1]; + build_table_filename(path, sizeof(path) - 1, + t->db, t->table_name, reg_ext, 0); + /* + Note that we can't be 100% sure that it is a view since it's + possible that we either simply have not found unused TABLE + instance in THD::open_tables list or were unable to open table + during prelocking process (in this case in theory we still + should hold shared metadata lock on it). + */ + if (dd_frm_is_view(thd, path)) + { + /* + If parent_l of the table_list is non null then a merge table + has this view as child table, which is not supported. + */ + if (t->parent_l) + { + my_error(ER_WRONG_MRG_TABLE, MYF(0)); + DBUG_RETURN(FALSE); + } + + if (!tdc_open_view(thd, t, CHECK_METADATA_VERSION)) + { + DBUG_ASSERT(t->view != 0); + DBUG_RETURN(TRUE); // VIEW + } + } + } + + DBUG_RETURN(FALSE); +} + + +/** Open a base table. @param thd Thread context. @@ -1608,49 +1669,10 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx) DBUG_PRINT("info",("Using locked table")); goto reset; } - /* - Is this table a view and not a base table? - (it is work around to allow to open view with locked tables, - real fix will be made after definition cache will be made) - Since opening of view which was not explicitly locked by LOCK - TABLES breaks metadata locking protocol (potentially can lead - to deadlocks) it should be disallowed. - */ - if (thd->mdl_context.is_lock_owner(MDL_key::TABLE, - table_list->db, - table_list->table_name, - MDL_SHARED)) - { - char path[FN_REFLEN + 1]; - build_table_filename(path, sizeof(path) - 1, - table_list->db, table_list->table_name, reg_ext, 0); - /* - Note that we can't be 100% sure that it is a view since it's - possible that we either simply have not found unused TABLE - instance in THD::open_tables list or were unable to open table - during prelocking process (in this case in theory we still - should hold shared metadata lock on it). - */ - if (dd_frm_is_view(thd, path)) - { - /* - If parent_l of the table_list is non null then a merge table - has this view as child table, which is not supported. - */ - if (table_list->parent_l) - { - my_error(ER_WRONG_MRG_TABLE, MYF(0)); - DBUG_RETURN(true); - } + if (is_locked_view(thd, table_list)) + DBUG_RETURN(FALSE); // VIEW - if (!tdc_open_view(thd, table_list, CHECK_METADATA_VERSION)) - { - DBUG_ASSERT(table_list->view != 0); - DBUG_RETURN(FALSE); // VIEW - } - } - } /* No table in the locked tables list. In case of explicit LOCK TABLES this can happen if a user did not include the table into the list. @@ -2003,8 +2025,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 @@ -2017,15 +2040,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; } /* @@ -2037,9 +2060,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 && @@ -2047,10 +2069,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 (unlikely(!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; } @@ -3816,7 +3849,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; } @@ -4213,8 +4246,9 @@ handle_routine(THD *thd, Query_tables_list *prelocking_ctx, @note this can be changed to use a hash, instead of scanning the linked list, if the performance of this function will ever become an issue */ -static bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_STRING *db, - LEX_STRING *table, thr_lock_type lock_type) + +bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_STRING *db, + LEX_STRING *table, thr_lock_type lock_type) { for (; tl; tl= tl->next_global ) { @@ -6673,10 +6707,22 @@ store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join, result= FALSE; -err: if (arena) thd->restore_active_arena(arena, &backup); DBUG_RETURN(result); + +err: + /* + Actually we failed to build join columns list, so we have to + clear it to avoid problems with half-build join on next run. + The list was created in mark_common_columns(). + */ + table_ref_1->remove_join_columns(); + table_ref_2->remove_join_columns(); + + if (arena) + thd->restore_active_arena(arena, &backup); + DBUG_RETURN(TRUE); } |