diff options
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r-- | sql/sql_table.cc | 143 |
1 files changed, 39 insertions, 104 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5052e29ac30..6fbee4f856e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -27,8 +27,8 @@ // start_waiting_global_read_lock, // unlock_table_names, mysql_unlock_tables #include "strfunc.h" // find_type2, find_set -#include "sql_view.h" // mysql_frm_type, view_checksum, mysql_frm_type -#include "sql_delete.h" // mysql_truncate +#include "sql_view.h" // view_checksum +#include "sql_truncate.h" // regenerate_locked_table #include "sql_partition.h" // mem_alloc_error, // generate_partition_syntax, // partition_info @@ -52,6 +52,7 @@ #include "sql_show.h" #include "transaction.h" #include "keycaches.h" +#include "datadict.h" // dd_frm_type() #ifdef __WIN__ #include <io.h> @@ -2125,7 +2126,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, ((access(path, F_OK) && ha_create_table_from_engine(thd, db, alias)) || (!drop_view && - mysql_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE))) + dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE))) { // Table was not found on disk and table can't be created from engine if (if_exists) @@ -2145,7 +2146,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, */ if (frm_db_type == DB_TYPE_UNKNOWN) { - mysql_frm_type(thd, path, &frm_db_type); + dd_frm_type(thd, path, &frm_db_type); DBUG_PRINT("info", ("frm_db_type %d from %s", frm_db_type, path)); } table_type= ha_resolve_by_legacy_type(thd, frm_db_type); @@ -4454,10 +4455,10 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, char from[FN_REFLEN],tmp[FN_REFLEN+32]; const char **ext; MY_STAT stat_info; - Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); + Open_table_context ot_ctx(thd, (MYSQL_OPEN_IGNORE_FLUSH | + MYSQL_OPEN_HAS_MDL_LOCK | + MYSQL_LOCK_IGNORE_TIMEOUT)); DBUG_ENTER("prepare_for_repair"); - uint reopen_for_repair_flags= (MYSQL_OPEN_IGNORE_FLUSH | - MYSQL_OPEN_HAS_MDL_LOCK); if (!(check_opt->sql_flags & TT_USEFRM)) DBUG_RETURN(0); @@ -4586,12 +4587,18 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, "Failed renaming data file"); goto end; } - if (mysql_truncate(thd, table_list, 1)) + if (dd_recreate_table(thd, table_list->db, table_list->table_name)) { error= send_check_errmsg(thd, table_list, "repair", "Failed generating table from .frm file"); goto end; } + /* + 'FALSE' for 'using_transactions' means don't postpone + invalidation till the end of a transaction, but do it + immediately. + */ + query_cache_invalidate3(thd, table_list, FALSE); if (mysql_file_rename(key_file_misc, tmp, from, MYF(MY_WME))) { error= send_check_errmsg(thd, table_list, "repair", @@ -4606,8 +4613,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, Now we should be able to open the partially repaired table to finish the repair in the handler later on. */ - if (open_table(thd, table_list, thd->mem_root, - &ot_ctx_unused, reopen_for_repair_flags)) + if (open_table(thd, table_list, thd->mem_root, &ot_ctx)) { error= send_check_errmsg(thd, table_list, "repair", "Failed to open partially repaired table"); @@ -4685,6 +4691,14 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, strxmov(table_name, db, ".", table->table_name, NullS); thd->open_options|= extra_open_options; table->lock_type= lock_type; + /* + To make code safe for re-execution we need to reset type of MDL + request as code below may change it. + To allow concurrent execution of read-only operations we acquire + weak metadata lock for them. + */ + table->mdl_request.set_type((lock_type >= TL_WRITE_ALLOW_WRITE) ? + MDL_SHARED_NO_READ_WRITE : MDL_SHARED_READ); /* open only one table from local list of command */ { TABLE_LIST *save_next_global, *save_next_local; @@ -4706,8 +4720,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (view_operator_func == NULL) table->required_type=FRMTYPE_TABLE; - open_error= open_and_lock_tables(thd, table, TRUE, - MYSQL_OPEN_TAKE_UPGRADABLE_MDL); + open_error= open_and_lock_tables(thd, table, TRUE, 0); thd->no_warnings_for_error= 0; table->next_global= save_next_global; table->next_local= save_next_local; @@ -5053,6 +5066,7 @@ send_result_message: /* Clear the ticket released in close_thread_tables(). */ table->mdl_request.ticket= NULL; DEBUG_SYNC(thd, "ha_admin_open_ltable"); + table->mdl_request.set_type(MDL_SHARED_WRITE); if ((table->table= open_ltable(thd, table, lock_type, 0))) { result_code= table->table->file->ha_analyze(thd, check_opt); @@ -5388,7 +5402,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, char buf[2048]; String query(buf, sizeof(buf), system_charset_info); query.length(0); // Have to zero it since constructor doesn't - Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); + Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); /* The condition avoids a crash as described in BUG#48506. Other @@ -5403,8 +5417,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, to work. The table will be closed by close_thread_table() at the end of this branch. */ - if (open_table(thd, table, thd->mem_root, &ot_ctx_unused, - MYSQL_OPEN_REOPEN)) + if (open_table(thd, table, thd->mem_root, &ot_ctx)) goto err; int result __attribute__((unused))= @@ -5490,6 +5503,7 @@ mysql_discard_or_import_tablespace(THD *thd, not complain when we lock the table */ thd->tablespace_op= TRUE; + table_list->mdl_request.set_type(MDL_SHARED_WRITE); if (!(table=open_ltable(thd, table_list, TL_WRITE, 0))) { thd->tablespace_op=FALSE; @@ -6467,8 +6481,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, char reg_path[FN_REFLEN+1]; ha_rows copied,deleted; handlerton *old_db_type, *new_db_type, *save_old_db_type; - legacy_db_type table_type; - frm_type_enum frm_type; enum_alter_table_change_level need_copy_table= ALTER_TABLE_METADATA_ONLY; #ifdef WITH_PARTITION_STORAGE_ENGINE uint fast_alter_partition= 0; @@ -6548,85 +6560,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, /* Conditionally writes to binlog. */ DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list, alter_info->tablespace_op)); - strxnmov(new_name_buff, sizeof (new_name_buff) - 1, mysql_data_home, "/", db, - "/", table_name, reg_ext, NullS); - (void) unpack_filename(new_name_buff, new_name_buff); - /* - If this is just a rename of a view, short cut to the - following scenario: 1) lock LOCK_open 2) do a RENAME - 2) unlock LOCK_open. - This is a copy-paste added to make sure - ALTER (sic:) TABLE .. RENAME works for views. ALTER VIEW is handled - as an independent branch in mysql_execute_command. The need - for a copy-paste arose because the main code flow of ALTER TABLE - ... RENAME tries to use open_ltable, which does not work for views - (open_ltable was never modified to merge table lists of child tables - into the main table list, like open_tables does). - This code is wrong and will be removed, please do not copy. - */ - frm_type= mysql_frm_type(thd, new_name_buff, &table_type); - /* Rename a view */ - /* Sic: there is a race here */ - if (frm_type == FRMTYPE_VIEW && !(alter_info->flags & ~ALTER_RENAME)) - { - /* - The following branch handles "ALTER VIEW v1 /no arguments/;" - This feature is not documented one. - However, before "OPTIMIZE TABLE t1;" was implemented, - ALTER TABLE with no alter_specifications was used to force-rebuild - the table. That's why this grammar is allowed. That's why we ignore - it for views. So just do nothing in such a case. - */ - if (!new_name) - { - my_ok(thd); - DBUG_RETURN(FALSE); - } - - /* - Avoid problems with a rename on a table that we have locked or - if the user is trying to to do this in a transcation context - */ - - if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction()) - { - my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, - ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); - DBUG_RETURN(TRUE); - } - - if (thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE)) - DBUG_RETURN(TRUE); - if (lock_table_names(thd, table_list)) - { - error= 1; - goto view_err; - } - - mysql_mutex_lock(&LOCK_open); - - if (!do_rename(thd, table_list, new_db, new_name, new_name, 1)) - { - if (mysql_bin_log.is_open()) - { - thd->clear_error(); - Query_log_event qinfo(thd, thd->query(), thd->query_length(), - FALSE, TRUE, FALSE, 0); - if ((error= mysql_bin_log.write(&qinfo))) - goto view_err_unlock; - } - my_ok(thd); - } - -view_err_unlock: - mysql_mutex_unlock(&LOCK_open); - unlock_table_names(thd); - -view_err: - thd->global_read_lock.start_waiting_global_read_lock(thd); - DBUG_RETURN(error); - } - /* Code below can handle only base tables so ensure that we won't open a view. @@ -6637,8 +6570,7 @@ view_err: Alter_table_prelocking_strategy alter_prelocking_strategy(alter_info); - error= open_and_lock_tables(thd, table_list, FALSE, - MYSQL_OPEN_TAKE_UPGRADABLE_MDL, + error= open_and_lock_tables(thd, table_list, FALSE, 0, &alter_prelocking_strategy); if (error) @@ -7241,14 +7173,14 @@ view_err: { if (table->s->tmp_table) { - Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); + Open_table_context ot_ctx(thd, (MYSQL_OPEN_IGNORE_FLUSH | + MYSQL_LOCK_IGNORE_TIMEOUT)); TABLE_LIST tbl; bzero((void*) &tbl, sizeof(tbl)); tbl.db= new_db; tbl.table_name= tbl.alias= tmp_name; /* Table is in thd->temporary_tables */ - (void) open_table(thd, &tbl, thd->mem_root, &ot_ctx_unused, - MYSQL_OPEN_IGNORE_FLUSH); + (void) open_table(thd, &tbl, thd->mem_root, &ot_ctx); new_table= tbl.table; } else @@ -7527,7 +7459,7 @@ view_err: To do this we need to obtain a handler object for it. NO need to tamper with MERGE tables. The real open is done later. */ - Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); + Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); TABLE *t_table; if (new_name != table_name || new_db != db) { @@ -7547,8 +7479,7 @@ view_err: */ table_list->mdl_request.ticket= mdl_ticket; } - if (open_table(thd, table_list, thd->mem_root, - &ot_ctx_unused, MYSQL_OPEN_REOPEN)) + if (open_table(thd, table_list, thd->mem_root, &ot_ctx)) { goto err_with_mdl; } @@ -7940,6 +7871,10 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list) table_list->table= NULL; /* Same applies to MDL ticket. */ table_list->mdl_request.ticket= NULL; + /* Set lock type which is appropriate for ALTER TABLE. */ + table_list->lock_type= TL_READ_NO_INSERT; + /* Same applies to MDL request. */ + table_list->mdl_request.set_type(MDL_SHARED_NO_WRITE); bzero((char*) &create_info, sizeof(create_info)); create_info.row_type=ROW_TYPE_NOT_USED; |