diff options
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 655 |
1 files changed, 282 insertions, 373 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 88cb16e3e7d..1e6bf3f0213 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -30,9 +30,6 @@ #include "sql_view.h" // mysql_make_view, VIEW_ANY_ACL #include "sql_parse.h" // check_table_access #include "sql_insert.h" // kill_delayed_threads -#include "sql_acl.h" // *_ACL, check_grant_all_columns, - // check_column_grant_in_table_ref, - // get_column_grant #include "sql_partition.h" // ALTER_PARTITION_PARAM_TYPE #include "sql_derived.h" // mysql_derived_prepare, // mysql_handle_derived, @@ -56,7 +53,6 @@ #include "rpl_filter.h" #include "sql_table.h" // build_table_filename #include "datadict.h" // dd_frm_is_view() -#include "sql_hset.h" // Hash_set #include "rpl_rli.h" // rpl_group_info #ifdef __WIN__ #include <io.h> @@ -262,7 +258,7 @@ static my_bool list_open_tables_callback(TDC_element *element, arg->table_list.db.length= db_length; arg->table_list.table_name.str= table_name; arg->table_list.table_name.length= strlen(table_name); - arg->table_list.grant.privilege= 0; + arg->table_list.grant.privilege= NO_ACL; if (check_table_access(arg->thd, SELECT_ACL, &arg->table_list, TRUE, 1, TRUE)) return FALSE; @@ -312,13 +308,9 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild) /** Close all tables that are not in use in table definition cache - - @param purge_flag Argument for tc_purge. true if we should force all - shares to be deleted. false if it's enough to just - evict those that are not in use. */ -void purge_tables(bool purge_flag) +void purge_tables() { /* Force close of all open tables. @@ -332,7 +324,7 @@ void purge_tables(bool purge_flag) Get rid of all unused TABLE and TABLE_SHARE instances. By doing this we automatically close all tables which were marked as "old". */ - tc_purge(purge_flag); + tc_purge(); /* Free table shares which were not freed implicitly by loop above. */ tdc_purge(true); } @@ -361,7 +353,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, if (!tables) { /* Free tables that are not used */ - purge_tables(false); + purge_tables(); if (!wait_for_refresh) DBUG_RETURN(false); } @@ -396,13 +388,12 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, if (! table) continue; - if (thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, MDL_EXCLUSIVE, - timeout)) + if (wait_while_table_is_used(thd, table, + HA_EXTRA_PREPARE_FOR_FORCED_CLOSE)) { result= true; break; } - table->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE); close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED, NULL); } /* @@ -442,7 +433,8 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, MDL_request *mdl_request= new (thd->mem_root) MDL_request; if (mdl_request == NULL) DBUG_RETURN(true); - mdl_request->init(&table->mdl_request.key, MDL_EXCLUSIVE, MDL_STATEMENT); + MDL_REQUEST_INIT_BY_KEY(mdl_request, &table->mdl_request.key, + MDL_EXCLUSIVE, MDL_STATEMENT); mdl_requests.push_front(mdl_request); } @@ -450,8 +442,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, DBUG_RETURN(true); for (TABLE_LIST *table= tables; table; table= table->next_local) - tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db.str, - table->table_name.str, false); + tdc_remove_table(thd, table->db.str, table->table_name.str); } DBUG_RETURN(false); } @@ -562,7 +553,7 @@ bool flush_tables(THD *thd, flush_tables_type flag) flush_tables_error_handler error_handler; DBUG_ENTER("flush_tables"); - purge_tables(false); /* Flush unused tables and shares */ + purge_tables(); /* Flush unused tables and shares */ /* Loop over all shares and collect shares that have open tables @@ -571,12 +562,12 @@ bool flush_tables(THD *thd, flush_tables_type flag) write after last time all tables was closed. */ - if (!(tmp_table= (TABLE*) my_malloc(sizeof(*tmp_table), + if (!(tmp_table= (TABLE*) my_malloc(PSI_INSTRUMENT_ME, sizeof(*tmp_table), MYF(MY_WME | MY_THREAD_SPECIFIC)))) DBUG_RETURN(1); - my_init_dynamic_array(&collect_arg.shares, sizeof(TABLE_SHARE*), 100, 100, - MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &collect_arg.shares, + sizeof(TABLE_SHARE*), 100, 100, MYF(0)); collect_arg.flush_type= flag; if (tdc_iterate(thd, (my_hash_walk_action) tc_collect_used_shares, &collect_arg, true)) @@ -607,12 +598,15 @@ bool flush_tables(THD *thd, flush_tables_type flag) else { /* - HA_OPEN_FOR_ALTER is used to allow us to open the table even if - TABLE_SHARE::incompatible_version is set. + HA_OPEN_FOR_FLUSH is used to allow us to open the table even if + TABLE_SHARE::incompatible_version is set. It also will tell + SEQUENCE engine that we don't have to read the sequence information + (which may cause deadlocks with concurrently running ALTER TABLE or + ALTER SEQUENCE) as we will close the table at once. */ if (!open_table_from_share(thd, share, &empty_clex_str, HA_OPEN_KEYFILE, 0, - HA_OPEN_FOR_ALTER, + HA_OPEN_FOR_ALTER | HA_OPEN_FOR_FLUSH, tmp_table, FALSE, NULL)) { @@ -638,93 +632,6 @@ err: } -/** - Close all tables which match specified connection string or - if specified string is NULL, then any table with a connection string. -*/ - -struct close_cached_connection_tables_arg -{ - THD *thd; - LEX_CSTRING *connection; - TABLE_LIST *tables; -}; - - -static my_bool close_cached_connection_tables_callback( - TDC_element *element, close_cached_connection_tables_arg *arg) -{ - TABLE_LIST *tmp; - - mysql_mutex_lock(&element->LOCK_table_share); - /* Ignore if table is not open or does not have a connect_string */ - if (!element->share || !element->share->connect_string.length || - !element->ref_count) - goto end; - - /* Compare the connection string */ - if (arg->connection && - (arg->connection->length > element->share->connect_string.length || - (arg->connection->length < element->share->connect_string.length && - (element->share->connect_string.str[arg->connection->length] != '/' && - element->share->connect_string.str[arg->connection->length] != '\\')) || - strncasecmp(arg->connection->str, element->share->connect_string.str, - arg->connection->length))) - goto end; - - /* close_cached_tables() only uses these elements */ - if (!(tmp= (TABLE_LIST*) alloc_root(arg->thd->mem_root, sizeof(TABLE_LIST))) || - !(arg->thd->make_lex_string(&tmp->db, element->share->db.str, element->share->db.length)) || - !(arg->thd->make_lex_string(&tmp->table_name, element->share->table_name.str, - element->share->table_name.length))) - { - mysql_mutex_unlock(&element->LOCK_table_share); - return TRUE; - } - - tmp->next_local= arg->tables; - arg->tables= tmp; - -end: - mysql_mutex_unlock(&element->LOCK_table_share); - return FALSE; -} - - -/** - Close cached connections - - @return false ok - @return true If there was an error from closed_cached_connection_tables or - if there was any open connections that we had to force closed -*/ - -bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection) -{ - bool res= false; - close_cached_connection_tables_arg argument; - DBUG_ENTER("close_cached_connections"); - DBUG_ASSERT(thd); - - argument.thd= thd; - argument.connection= connection; - argument.tables= NULL; - - if (tdc_iterate(thd, - (my_hash_walk_action) close_cached_connection_tables_callback, - &argument)) - DBUG_RETURN(true); - - for (TABLE_LIST *table= argument.tables; table; table= table->next_local) - res|= tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED, - table->db.str, - table->table_name.str, TRUE); - - /* Return true if we found any open connections */ - DBUG_RETURN(res); -} - - /* Mark all tables in the list which were used by current substatement as free for reuse. @@ -741,8 +648,9 @@ bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection) Clear 'check_table_binlog_row_based_done' flag. For tables which were used by current substatement the flag is cleared as part of 'ha_reset()' call. For the rest of the open tables not used by current substament if this - flag is enabled as part of current substatement execution, clear the flag - explicitly. + flag is enabled as part of current substatement execution, + (for example when THD::binlog_write_table_maps() calls + prepare_for_row_logging()), clear the flag explicitly. NOTE The reason we reset query_id is that it's not enough to just test @@ -766,7 +674,7 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table) table->query_id= 0; table->file->ha_reset(); } - else if (table->file->check_table_binlog_row_based_done) + else table->file->clear_cached_table_binlog_row_based_flag(); } DBUG_VOID_RETURN; @@ -806,11 +714,10 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share, TABLE *skip_table) { DBUG_ASSERT(!share->tmp_table); + DBUG_ASSERT(share->tdc->flushed); char key[MAX_DBKEY_LENGTH]; size_t key_length= share->table_cache_key.length; - const char *db= key; - const char *table_name= db + share->db.length + 1; bool remove_from_locked_tables= extra != HA_EXTRA_NOT_USED; memcpy(key, share->table_cache_key.str, key_length); @@ -847,12 +754,6 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share, prev= &table->next; } } - if (skip_table == NULL) - { - /* Remove the table share from the cache. */ - tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db, table_name, - FALSE); - } } @@ -874,9 +775,10 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share, leave prelocked mode if needed. */ -void close_thread_tables(THD *thd) +int close_thread_tables(THD *thd) { TABLE *table; + int error= 0; DBUG_ENTER("close_thread_tables"); THD_STAGE_INFO(thd, stage_closing_tables); @@ -894,14 +796,11 @@ void close_thread_tables(THD *thd) DEBUG_SYNC(thd, "before_close_thread_tables"); #endif - DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt || + DBUG_ASSERT(thd->transaction->stmt.is_empty() || thd->in_sub_stmt || (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); for (table= thd->open_tables; table; table= table->next) { - if (table->update_handler) - table->delete_update_handler(); - /* Table might be in use by some outer statement. */ DBUG_PRINT("tcache", ("table: '%s' query_id: %lu", table->s->table_name.str, (ulong) table->query_id)); @@ -979,7 +878,7 @@ void close_thread_tables(THD *thd) we will exit this function a few lines below. */ if (! thd->lex->requires_prelocking()) - DBUG_VOID_RETURN; + DBUG_RETURN(0); /* We are in the top-level statement of a prelocked statement, @@ -990,7 +889,7 @@ void close_thread_tables(THD *thd) thd->locked_tables_mode= LTM_LOCK_TABLES; if (thd->locked_tables_mode == LTM_LOCK_TABLES) - DBUG_VOID_RETURN; + DBUG_RETURN(0); thd->leave_locked_tables_mode(); @@ -1009,7 +908,7 @@ void close_thread_tables(THD *thd) binlog_query()) or when preparing a pending event. */ (void)thd->binlog_flush_pending_rows_event(TRUE); - mysql_unlock_tables(thd, thd->lock); + error= mysql_unlock_tables(thd, thd->lock); thd->lock=0; } /* @@ -1019,7 +918,7 @@ void close_thread_tables(THD *thd) while (thd->open_tables) (void) close_thread_table(thd, &thd->open_tables); - DBUG_VOID_RETURN; + DBUG_RETURN(error); } @@ -1405,21 +1304,24 @@ bool wait_while_table_is_used(THD *thd, TABLE *table, { DBUG_ENTER("wait_while_table_is_used"); DBUG_ASSERT(!table->s->tmp_table); - DBUG_PRINT("enter", ("table: '%s' share: %p db_stat: %u version: %lld", + DBUG_PRINT("enter", ("table: '%s' share: %p db_stat: %u", table->s->table_name.str, table->s, - table->db_stat, table->s->tdc->version)); + table->db_stat)); if (thd->mdl_context.upgrade_shared_lock( table->mdl_ticket, MDL_EXCLUSIVE, thd->variables.lock_wait_timeout)) DBUG_RETURN(TRUE); - tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN, - table->s->db.str, table->s->table_name.str, - FALSE); + table->s->tdc->flush(thd, true); /* extra() call must come only after all instances above are closed */ if (function != HA_EXTRA_NOT_USED) - DBUG_RETURN(table->file->extra(function)); + { + int error= table->file->extra(function); + if (error) + table->file->print_error(error, MYF(0)); + DBUG_RETURN(error); + } DBUG_RETURN(FALSE); } @@ -1455,10 +1357,8 @@ void drop_open_table(THD *thd, TABLE *table, const LEX_CSTRING *db_name, handlerton *table_type= table->s->db_type(); table->file->extra(HA_EXTRA_PREPARE_FOR_DROP); + table->s->tdc->flush(thd, true); close_thread_table(thd, &thd->open_tables); - /* Remove the table share from the table cache. */ - tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db_name->str, table_name->str, - FALSE); /* Remove the table from the storage engine and rm the .frm. */ quick_rm_table(thd, table_type, db_name, table_name, 0); } @@ -1587,10 +1487,9 @@ open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx, DBUG_ASSERT(!(flags & MYSQL_OPEN_FORCE_SHARED_MDL) || !(flags & MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)); - mdl_request_shared.init(&mdl_request->key, - (flags & MYSQL_OPEN_FORCE_SHARED_MDL) ? - MDL_SHARED : MDL_SHARED_HIGH_PRIO, - MDL_TRANSACTION); + MDL_REQUEST_INIT_BY_KEY(&mdl_request_shared, &mdl_request->key, + flags & MYSQL_OPEN_FORCE_SHARED_MDL ? MDL_SHARED : MDL_SHARED_HIGH_PRIO, + MDL_TRANSACTION); mdl_request= &mdl_request_shared; } @@ -1676,9 +1575,10 @@ static int set_partitions_as_used(TABLE_LIST *tl, TABLE *t) 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"); + DBUG_ENTER("is_locked_view"); /* Is this table a view and not a base table? (it is work around to allow to open view with locked tables, @@ -2027,8 +1927,6 @@ retry_share: { if (share->tdc->flushed) { - DBUG_PRINT("info", ("Found old share version: %lld current: %lld", - share->tdc->version, tdc_refresh_version())); /* We already have an MDL lock. But we have encountered an old version of table in the table definition cache which is possible @@ -2080,7 +1978,14 @@ retry_share: if (table) { DBUG_ASSERT(table->file != NULL); - MYSQL_REBIND_TABLE(table->file); + if (table->file->discover_check_version()) + { + tc_release_table(table); + (void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER, + table_list); + DBUG_RETURN(TRUE); + } + table->file->rebind_psi(); #ifdef WITH_PARTITION_STORAGE_ENGINE part_names_error= set_partitions_as_used(table_list, table); #endif @@ -2089,7 +1994,8 @@ retry_share: { enum open_frm_error error; /* make a new table */ - if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME)))) + if (!(table=(TABLE*) my_malloc(key_memory_TABLE, sizeof(*table), + MYF(MY_WME)))) goto err_lock; error= open_table_from_share(thd, share, &table_list->alias, @@ -2175,8 +2081,8 @@ retry_share: DBUG_RETURN(TRUE); } - protection_request.init(MDL_key::BACKUP, "", "", mdl_type, - MDL_STATEMENT); + MDL_REQUEST_INIT(&protection_request, MDL_key::BACKUP, "", "", mdl_type, + MDL_STATEMENT); /* Install error handler which if possible will convert deadlock error @@ -2238,13 +2144,14 @@ retry_share: DBUG_RETURN(true); } - DBUG_RETURN(FALSE); + DBUG_ASSERT(thd->locked_tables_mode || table->file->row_logging == 0); + DBUG_RETURN(false); err_lock: tdc_release_share(share); DBUG_PRINT("exit", ("failed")); - DBUG_RETURN(TRUE); + DBUG_RETURN(true); } @@ -2436,9 +2343,10 @@ Locked_tables_list::init_locked_tables(THD *thd) @note This function is a no-op if we're not in LOCK TABLES. */ -void +int Locked_tables_list::unlock_locked_tables(THD *thd) { + int error; DBUG_ASSERT(!thd->in_sub_stmt && !(thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); /* @@ -2448,7 +2356,7 @@ Locked_tables_list::unlock_locked_tables(THD *thd) open tables, e.g. from begin_trans(). */ if (thd->locked_tables_mode != LTM_LOCK_TABLES) - return; + return 0; for (TABLE_LIST *table_list= m_locked_tables; table_list; table_list= table_list->next_global) @@ -2464,8 +2372,8 @@ Locked_tables_list::unlock_locked_tables(THD *thd) TRANSACT_TRACKER(clear_trx_state(thd, TX_LOCKED_TABLES)); - DBUG_ASSERT(thd->transaction.stmt.is_empty()); - close_thread_tables(thd); + DBUG_ASSERT(thd->transaction->stmt.is_empty()); + error= close_thread_tables(thd); /* We rely on the caller to implicitly commit the @@ -2477,6 +2385,7 @@ Locked_tables_list::unlock_locked_tables(THD *thd) request for metadata locks and TABLE_LIST elements. */ reset(); + return error; } @@ -2485,7 +2394,7 @@ Locked_tables_list::unlock_locked_tables(THD *thd) table mode if there is no locked tables anymore */ -void +int Locked_tables_list::unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket) { /* @@ -2494,7 +2403,7 @@ Locked_tables_list::unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket) to check this condition here than in the caller. */ if (thd->locked_tables_mode != LTM_LOCK_TABLES) - return; + return 0; if (mdl_ticket) { @@ -2507,7 +2416,8 @@ Locked_tables_list::unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket) } if (thd->lock->table_count == 0) - unlock_locked_tables(thd); + return unlock_locked_tables(thd); + return 0; } @@ -2709,7 +2619,8 @@ Locked_tables_list::reopen_tables(THD *thd, bool need_reopen) /* Reset flag that some table was marked for reopen */ - some_table_marked_for_reopen= 0; + if (need_reopen) + some_table_marked_for_reopen= 0; for (TABLE_LIST *table_list= m_locked_tables; table_list; table_list= table_list->next_global) @@ -3076,16 +2987,13 @@ static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry) static bool auto_repair_table(THD *thd, TABLE_LIST *table_list) { TABLE_SHARE *share; - TABLE *entry; + TABLE entry; bool result= TRUE; thd->clear_error(); - if (!(entry= (TABLE*)my_malloc(sizeof(TABLE), MYF(MY_WME)))) - return result; - if (!(share= tdc_acquire_share(thd, table_list, GTS_TABLE))) - goto end_free; + return result; DBUG_ASSERT(! share->is_view); @@ -3093,31 +3001,25 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list) HA_OPEN_KEYFILE | HA_TRY_READ_ONLY, EXTRA_RECORD, ha_open_options | HA_OPEN_FOR_REPAIR, - entry, FALSE) || ! entry->file || - (entry->file->is_crashed() && entry->file->ha_check_and_repair(thd))) + &entry, FALSE) || ! entry.file || + (entry.file->is_crashed() && entry.file->ha_check_and_repair(thd))) { /* Give right error message */ thd->clear_error(); my_error(ER_NOT_KEYFILE, MYF(0), share->table_name.str); sql_print_error("Couldn't repair table: %s.%s", share->db.str, share->table_name.str); - if (entry->file) - closefrm(entry); + if (entry.file) + closefrm(&entry); } else { thd->clear_error(); // Clear error message - closefrm(entry); + closefrm(&entry); result= FALSE; } - tdc_release_share(share); - /* Remove the repaired share from the table cache. */ - tdc_remove_table(thd, TDC_RT_REMOVE_ALL, - table_list->db.str, table_list->table_name.str, - FALSE); -end_free: - my_free(entry); + tdc_remove_referenced_share(thd, share); return result; } @@ -3276,65 +3178,57 @@ Open_table_context::recover_from_failed_open() switch (m_action) { case OT_BACKOFF_AND_RETRY: - break; case OT_REOPEN_TABLES: break; case OT_DISCOVER: - { - if ((result= lock_table_names(m_thd, m_thd->lex->create_info, - m_failed_table, NULL, - get_timeout(), 0))) - break; - - tdc_remove_table(m_thd, TDC_RT_REMOVE_ALL, m_failed_table->db.str, - m_failed_table->table_name.str, FALSE); - - m_thd->get_stmt_da()->clear_warning_info(m_thd->query_id); - m_thd->clear_error(); // Clear error message + case OT_REPAIR: + if ((result= lock_table_names(m_thd, m_thd->lex->create_info, + m_failed_table, NULL, + get_timeout(), 0))) + break; - No_such_table_error_handler no_such_table_handler; - bool open_if_exists= m_failed_table->open_strategy == TABLE_LIST::OPEN_IF_EXISTS; + tdc_remove_table(m_thd, m_failed_table->db.str, + m_failed_table->table_name.str); - if (open_if_exists) - m_thd->push_internal_handler(&no_such_table_handler); - - result= !tdc_acquire_share(m_thd, m_failed_table, - GTS_TABLE | GTS_FORCE_DISCOVERY | GTS_NOLOCK); - if (open_if_exists) + switch (m_action) + { + case OT_DISCOVER: { - m_thd->pop_internal_handler(); - if (result && no_such_table_handler.safely_trapped_errors()) - result= FALSE; - } + m_thd->get_stmt_da()->clear_warning_info(m_thd->query_id); + m_thd->clear_error(); // Clear error message - /* - Rollback to start of the current statement to release exclusive lock - on table which was discovered but preserve locks from previous statements - in current transaction. - */ - m_thd->mdl_context.rollback_to_savepoint(start_of_statement_svp()); - break; - } - case OT_REPAIR: - { - if ((result= lock_table_names(m_thd, m_thd->lex->create_info, - m_failed_table, NULL, - get_timeout(), 0))) - break; + No_such_table_error_handler no_such_table_handler; + bool open_if_exists= m_failed_table->open_strategy == TABLE_LIST::OPEN_IF_EXISTS; - tdc_remove_table(m_thd, TDC_RT_REMOVE_ALL, m_failed_table->db.str, - m_failed_table->table_name.str, FALSE); + if (open_if_exists) + m_thd->push_internal_handler(&no_such_table_handler); - result= auto_repair_table(m_thd, m_failed_table); - /* - Rollback to start of the current statement to release exclusive lock - on table which was discovered but preserve locks from previous statements - in current transaction. - */ - m_thd->mdl_context.rollback_to_savepoint(start_of_statement_svp()); - break; + result= !tdc_acquire_share(m_thd, m_failed_table, + GTS_TABLE | GTS_FORCE_DISCOVERY | GTS_NOLOCK); + if (open_if_exists) + { + m_thd->pop_internal_handler(); + if (result && no_such_table_handler.safely_trapped_errors()) + result= FALSE; + } + break; + } + case OT_REPAIR: + result= auto_repair_table(m_thd, m_failed_table); + break; + case OT_BACKOFF_AND_RETRY: + case OT_REOPEN_TABLES: + case OT_NO_ACTION: + DBUG_ASSERT(0); } - default: + /* + Rollback to start of the current statement to release exclusive lock + on table which was discovered but preserve locks from previous statements + in current transaction. + */ + m_thd->mdl_context.rollback_to_savepoint(start_of_statement_svp()); + break; + case OT_NO_ACTION: DBUG_ASSERT(0); } m_thd->pop_internal_handler(); @@ -3790,10 +3684,11 @@ open_and_process_table(THD *thd, TABLE_LIST *tables, uint *counter, uint flags, temporary table or SEQUENCE (see sequence_insert()). */ DBUG_ASSERT(is_temporary_table(tables) || tables->table->s->sequence); - if (tables->sequence && tables->table->s->table_type != TABLE_TYPE_SEQUENCE) + if (tables->sequence && + tables->table->s->table_type != TABLE_TYPE_SEQUENCE) { - my_error(ER_NOT_SEQUENCE, MYF(0), tables->db.str, tables->alias.str); - DBUG_RETURN(true); + my_error(ER_NOT_SEQUENCE, MYF(0), tables->db.str, tables->alias.str); + DBUG_RETURN(true); } } else if (tables->open_type == OT_TEMPORARY_ONLY) @@ -3847,9 +3742,9 @@ open_and_process_table(THD *thd, TABLE_LIST *tables, uint *counter, uint flags, The problem is that since those attributes are not set in merge children, another round of PREPARE will not help. */ - error= thd->open_temporary_table(tables); - - if (!error && !tables->table) + if (!thd->has_temporary_tables() || + (!(error= thd->open_temporary_table(tables)) && + !tables->table)) error= open_table(thd, tables, ot_ctx); thd->pop_internal_handler(); @@ -3866,9 +3761,9 @@ open_and_process_table(THD *thd, TABLE_LIST *tables, uint *counter, uint flags, Repair_mrg_table_error_handler repair_mrg_table_handler; thd->push_internal_handler(&repair_mrg_table_handler); - error= thd->open_temporary_table(tables); - - if (!error && !tables->table) + if (!thd->has_temporary_tables() || + (!(error= thd->open_temporary_table(tables)) && + !tables->table)) error= open_table(thd, tables, ot_ctx); thd->pop_internal_handler(); @@ -3883,7 +3778,8 @@ open_and_process_table(THD *thd, TABLE_LIST *tables, uint *counter, uint flags, still might need to look for a temporary table if this table list element corresponds to underlying table of a merge table. */ - error= thd->open_temporary_table(tables); + if (thd->has_temporary_tables()) + error= thd->open_temporary_table(tables); } if (!error && !tables->table) @@ -4006,7 +3902,8 @@ static bool upgrade_lock_if_not_exists(THD *thd, { DEBUG_SYNC(thd,"create_table_before_check_if_exists"); if (!create_info.or_replace() && - ha_table_exists(thd, &create_table->db, &create_table->table_name)) + ha_table_exists(thd, &create_table->db, &create_table->table_name, + &create_table->db_type)) { if (create_info.if_not_exists()) { @@ -4054,7 +3951,8 @@ static bool upgrade_lock_if_not_exists(THD *thd, Note that for CREATE TABLE IF EXISTS we only generate a warning but still return TRUE (to abort the calling open_table() function). On must check THD->is_error() if one wants to distinguish between warning - and error. + and error. If table existed, tables_start->db_type is set to the handlerton + for the found table. */ bool @@ -4096,9 +3994,8 @@ lock_table_names(THD *thd, const DDL_options_st &options, MDL_request *schema_request= new (thd->mem_root) MDL_request; if (schema_request == NULL) DBUG_RETURN(TRUE); - schema_request->init(MDL_key::SCHEMA, table->db.str, "", - MDL_INTENTION_EXCLUSIVE, - MDL_TRANSACTION); + MDL_REQUEST_INIT(schema_request, MDL_key::SCHEMA, table->db.str, "", + MDL_INTENTION_EXCLUSIVE, MDL_TRANSACTION); mdl_requests.push_front(schema_request); } @@ -4120,7 +4017,8 @@ lock_table_names(THD *thd, const DDL_options_st &options, if (thd->has_read_only_protection()) DBUG_RETURN(true); - global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, MDL_STATEMENT); + MDL_REQUEST_INIT(&global_request, MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, + MDL_STATEMENT); mdl_savepoint= thd->mdl_context.mdl_savepoint(); while (!thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout) && @@ -4274,9 +4172,9 @@ bool open_tables(THD *thd, const DDL_options_st &options, for (TABLE_LIST *table= *start; table; table= table->next_global) if (!table->schema_table) { - if (thd->transaction.xid_state.check_has_uncommitted_xa()) + if (thd->transaction->xid_state.check_has_uncommitted_xa()) { - thd->transaction.xid_state.er_xaer_rmfail(); + thd->transaction->xid_state.er_xaer_rmfail(); DBUG_RETURN(true); } else @@ -4422,7 +4320,7 @@ restart: list, we still need to call open_and_process_routine() to take MDL locks on the routines. */ - if (thd->locked_tables_mode <= LTM_LOCK_TABLES) + if (thd->locked_tables_mode <= LTM_LOCK_TABLES && *sroutine_to_open) { /* Process elements of the prelocking set which are present there @@ -5326,7 +5224,9 @@ bool open_and_lock_tables(THD *thd, const DDL_options_st &options, if (lock_tables(thd, tables, counter, flags)) goto err; - (void) read_statistics_for_tables_if_needed(thd, tables); + /* Don't read statistics tables when opening internal tables */ + if (!(flags & MYSQL_OPEN_IGNORE_LOGGING_FORMAT)) + (void) read_statistics_for_tables_if_needed(thd, tables); if (derived) { @@ -5388,7 +5288,7 @@ end: table on the fly, and thus mustn't manipulate with the transaction of the enclosing statement. */ - DBUG_ASSERT(thd->transaction.stmt.is_empty() || + DBUG_ASSERT(thd->transaction->stmt.is_empty() || (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); close_thread_tables(thd); /* Don't keep locks for a failed statement. */ @@ -5459,12 +5359,19 @@ bool open_tables_only_view_structure(THD *thd, TABLE_LIST *table_list, static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table_list) { TABLE_LIST *table; + DBUG_ENTER("mark_real_tables_as_free_for_reuse"); + + /* + We have to make two loops as HA_EXTRA_DETACH_CHILDREN may + remove items from the table list that we have to reset + */ for (table= table_list; table; table= table->next_global) + { if (!table->placeholder()) - { table->table->query_id= 0; - } + } for (table= table_list; table; table= table->next_global) + { if (!table->placeholder()) { /* @@ -5475,6 +5382,8 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table_list) */ table->table->file->extra(HA_EXTRA_DETACH_CHILDREN); } + } + DBUG_VOID_RETURN; } int TABLE::fix_vcol_exprs(THD *thd) @@ -5548,7 +5457,7 @@ static bool fix_all_session_vcol_exprs(THD *thd, TABLE_LIST *tables) bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, uint flags) { - TABLE_LIST *table; + TABLE_LIST *table, *first_not_own; DBUG_ENTER("lock_tables"); /* We can't meet statement requiring prelocking if we already @@ -5558,7 +5467,9 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, uint flags) !thd->lex->requires_prelocking()); if (!tables && !thd->lex->requires_prelocking()) - DBUG_RETURN(thd->decide_logging_format(tables)); + DBUG_RETURN(0); + + first_not_own= thd->lex->first_not_own_table(); /* Check for thd->locked_tables_mode to avoid a redundant @@ -5574,13 +5485,26 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, uint flags) { DBUG_ASSERT(thd->lock == 0); // You must lock everything at once TABLE **start,**ptr; + bool found_first_not_own= 0; if (!(ptr=start=(TABLE**) thd->alloc(sizeof(TABLE*)*count))) DBUG_RETURN(TRUE); + + /* + Collect changes tables for table lock. + Mark own tables with query id as this is needed by + prepare_for_row_logging() + */ for (table= tables; table; table= table->next_global) { + if (table == first_not_own) + found_first_not_own= 1; if (!table->placeholder()) - *(ptr++)= table->table; + { + *(ptr++)= table->table; + if (!found_first_not_own) + table->table->query_id= thd->query_id; + } } DEBUG_SYNC(thd, "before_lock_tables_takes_lock"); @@ -5594,7 +5518,6 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, uint flags) if (thd->lex->requires_prelocking() && thd->lex->sql_command != SQLCOM_LOCK_TABLES) { - TABLE_LIST *first_not_own= thd->lex->first_not_own_table(); /* We just have done implicit LOCK TABLES, and now we have to emulate first open_and_lock_tables() after it. @@ -5612,7 +5535,6 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, uint flags) { if (!table->placeholder()) { - table->table->query_id= thd->query_id; if (check_lock_and_start_stmt(thd, thd->lex, table)) { mysql_unlock_tables(thd, thd->lock); @@ -5632,7 +5554,6 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, uint flags) } else { - TABLE_LIST *first_not_own= thd->lex->first_not_own_table(); /* When open_and_lock_tables() is called for a single table out of a table list, the 'next_global' chain is temporarily broken. We @@ -5648,6 +5569,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, uint flags) if (table->placeholder()) continue; + table->table->query_id= thd->query_id; /* In a stored function or trigger we should ensure that we won't change a table that is already used by the calling statement. @@ -5687,7 +5609,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, uint flags) } bool res= fix_all_session_vcol_exprs(thd, tables); - if (!res) + if (!res && !(flags & MYSQL_OPEN_IGNORE_LOGGING_FORMAT)) res= thd->decide_logging_format(tables); DBUG_RETURN(res); @@ -5772,7 +5694,7 @@ void close_tables_for_reopen(THD *thd, TABLE_LIST **tables, table on the fly, and thus mustn't manipulate with the transaction of the enclosing statement. */ - DBUG_ASSERT(thd->transaction.stmt.is_empty() || + DBUG_ASSERT(thd->transaction->stmt.is_empty() || (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); close_thread_tables(thd); thd->mdl_context.rollback_to_savepoint(start_of_statement_svp); @@ -5888,9 +5810,8 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, replace. If the item was aliased by the user, set the alias to the replacing item. */ - if (*ref && !(*ref)->is_autogenerated_name) - item->set_name(thd, (*ref)->name.str, (*ref)->name.length, - system_charset_info); + if (*ref && !(*ref)->is_autogenerated_name()) + item->set_name(thd, (*ref)->name); if (register_tree_change) thd->change_item_tree(ref, item); else @@ -5980,9 +5901,8 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, si replace. If the item was aliased by the user, set the alias to the replacing item. */ - if (*ref && !(*ref)->is_autogenerated_name) - item->set_name(thd, (*ref)->name.str, (*ref)->name.length, - system_charset_info); + if (*ref && !(*ref)->is_autogenerated_name()) + item->set_name(thd, (*ref)->name); if (register_tree_change && arena) thd->restore_active_arena(arena, &backup); @@ -6399,8 +6319,8 @@ find_field_in_tables(THD *thd, Item_ident *item, bool check_privileges, bool register_tree_change) { Field *found=0; - const char *db= item->db_name; - const char *table_name= item->table_name; + const char *db= item->db_name.str; + const char *table_name= item->table_name.str; const char *name= item->field_name.str; size_t length= item->field_name.length; char name_buff[SAFE_NAME_LEN+1]; @@ -6472,10 +6392,11 @@ find_field_in_tables(THD *thd, Item_ident *item, for (SELECT_LEX *sl= current_sel; sl && sl!=last_select; sl=sl->outer_select()) { - Item *subs= sl->master_unit()->item; - if (subs->type() == Item::SUBSELECT_ITEM && - ((Item_subselect*)subs)->substype() == Item_subselect::IN_SUBS && - ((Item_in_subselect*)subs)->test_strategy(SUBS_SEMI_JOIN)) + Item_in_subselect *in_subs= + sl->master_unit()->item->get_IN_subquery(); + if (in_subs && + in_subs->substype() == Item_subselect::IN_SUBS && + in_subs->test_strategy(SUBS_SEMI_JOIN)) { continue; } @@ -6676,8 +6597,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, if (is_ref_by_name) { field_name= &((Item_ident*) find)->field_name; - table_name= ((Item_ident*) find)->table_name; - db_name= ((Item_ident*) find)->db_name; + table_name= ((Item_ident*) find)->table_name.str; + db_name= ((Item_ident*) find)->db_name.str; } for (uint i= 0; i < n_items; i++) @@ -6717,13 +6638,13 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, item_field->field_name and item_field->table_name can be 0x0 if item is not fix_field()'ed yet. */ - if (item_field->field_name.str && item_field->table_name && + if (item_field->field_name.str && item_field->table_name.str && !lex_string_cmp(system_charset_info, &item_field->field_name, field_name) && - !my_strcasecmp(table_alias_charset, item_field->table_name, + !my_strcasecmp(table_alias_charset, item_field->table_name.str, table_name) && - (!db_name || (item_field->db_name && - !strcmp(item_field->db_name, db_name)))) + (!db_name || (item_field->db_name.str && + !strcmp(item_field->db_name.str, db_name)))) { if (found_unaliased) { @@ -7582,17 +7503,16 @@ static bool setup_natural_join_row_types(THD *thd, ****************************************************************************/ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, - List<Item> *sum_func_list, - uint wild_num, uint *hidden_bit_fields) + List<Item> *sum_func_list, SELECT_LEX *select_lex, bool returning_field) { - if (!wild_num) - return(0); - Item *item; List_iterator<Item> it(fields); Query_arena *arena, backup; DBUG_ENTER("setup_wild"); + if (!select_lex->with_wild) + DBUG_RETURN(0); + /* Don't use arena if we are not in prepared statements or stored procedures For PS/SP we have to use arena to remember the changes @@ -7600,7 +7520,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, arena= thd->activate_stmt_arena_if_needed(&backup); thd->lex->current_select->cur_pos_in_select_list= 0; - while (wild_num && (item= it++)) + while (select_lex->with_wild && (item= it++)) { if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name.str == star_clex_str.str && @@ -7621,9 +7541,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, MY_INT64_NUM_DECIMAL_DIGITS)); } else if (insert_fields(thd, ((Item_field*) item)->context, - ((Item_field*) item)->db_name, - ((Item_field*) item)->table_name, &it, - any_privileges, hidden_bit_fields)) + ((Item_field*) item)->db_name.str, + ((Item_field*) item)->table_name.str, &it, + any_privileges, &select_lex->hidden_bit_fields, returning_field)) { if (arena) thd->restore_active_arena(arena, &backup); @@ -7638,30 +7558,15 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, */ sum_func_list->elements+= fields.elements - elem; } - wild_num--; + select_lex->with_wild--; } else thd->lex->current_select->cur_pos_in_select_list++; } + DBUG_ASSERT(!select_lex->with_wild); thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS; if (arena) - { - /* make * substituting permanent */ - SELECT_LEX *select_lex= thd->lex->current_select; - select_lex->with_wild= 0; -#ifdef HAVE_valgrind - if (&select_lex->item_list != &fields) // Avoid warning -#endif - /* - The assignment below is translated to memcpy() call (at least on some - platforms). memcpy() expects that source and destination areas do not - overlap. That problem was detected by valgrind. - */ - if (&select_lex->item_list != &fields) - select_lex->item_list= fields; - thd->restore_active_arena(arena, &backup); - } DBUG_RETURN(0); } @@ -7782,6 +7687,26 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, /* + Perform checks like all given fields exists, if exists fill struct with + current data and expand all '*' in given fields for LEX::returning. + + SYNOPSIS + thd Thread handler + table_list Global/local table list +*/ + +int setup_returning_fields(THD* thd, TABLE_LIST* table_list) +{ + if (!thd->lex->has_returning()) + return 0; + return setup_wild(thd, table_list, thd->lex->returning()->item_list, NULL, + thd->lex->returning(), true) + || setup_fields(thd, Ref_ptr_array(), thd->lex->returning()->item_list, + MARK_COLUMNS_READ, NULL, NULL, false); +} + + +/* make list of leaves of join table tree SYNOPSIS @@ -8011,9 +7936,12 @@ bool setup_tables(THD *thd, Name_resolution_context *context, */ bool setup_tables_and_check_access(THD *thd, Name_resolution_context *context, List<TABLE_LIST> *from_clause, - TABLE_LIST *tables, List<TABLE_LIST> &leaves, - bool select_insert, ulong want_access_first, - ulong want_access, bool full_table_list) + TABLE_LIST *tables, + List<TABLE_LIST> &leaves, + bool select_insert, + privilege_t want_access_first, + privilege_t want_access, + bool full_table_list) { DBUG_ENTER("setup_tables_and_check_access"); @@ -8023,7 +7951,7 @@ bool setup_tables_and_check_access(THD *thd, Name_resolution_context *context, List_iterator<TABLE_LIST> ti(leaves); TABLE_LIST *table_list; - ulong access= want_access_first; + privilege_t access= want_access_first; while ((table_list= ti++)) { if (table_list->belong_to_view && !table_list->view && @@ -8067,7 +7995,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, name->length(), 1)) <= 0) { - my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), name->c_ptr(), + my_error(ER_KEY_DOES_NOT_EXISTS, MYF(0), name->c_ptr(), table->pos_in_table_list->alias.str); map->set_all(); return 1; @@ -8099,7 +8027,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, bool insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator<Item> *it, - bool any_privileges, uint *hidden_bit_fields) + bool any_privileges, uint *hidden_bit_fields, bool returning_field) { Field_iterator_table_ref field_iterator; bool found; @@ -8126,12 +8054,14 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, else treat natural joins as leaves and do not iterate over their underlying tables. */ - for (TABLE_LIST *tables= (table_name ? context->table_list : - context->first_name_resolution_table); - tables; - tables= (table_name ? tables->next_local : - tables->next_name_resolution_table) - ) + TABLE_LIST *first= context->first_name_resolution_table; + TABLE_LIST *TABLE_LIST::* next= &TABLE_LIST::next_name_resolution_table; + if (table_name && !returning_field) + { + first= context->table_list; + next= &TABLE_LIST::next_local; + } + for (TABLE_LIST *tables= first; tables; tables= tables->*next) { Field *field; TABLE *table= tables->table; @@ -8370,7 +8300,7 @@ bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update) */ if (embedded->sj_subq_pred) { - Item **left_expr= &embedded->sj_subq_pred->left_expr; + Item **left_expr= embedded->sj_subq_pred->left_exp_ptr(); if ((*left_expr)->fix_fields_if_needed(thd, left_expr)) return TRUE; } @@ -8839,8 +8769,8 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values, if (unlikely(field->invisible)) continue; - else - value=v++; + + value=v++; bool vers_sys_field= table->versioned() && field->vers_sys_field(); @@ -8937,7 +8867,7 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, Field **ptr, my_bool mysql_rm_tmp_tables(void) { uint i, idx; - char filePath[FN_REFLEN], *tmpdir, filePathCopy[FN_REFLEN]; + char path[FN_REFLEN], *tmpdir, path_copy[FN_REFLEN]; MY_DIR *dirp; FILEINFO *file; TABLE_SHARE share; @@ -8966,23 +8896,17 @@ my_bool mysql_rm_tmp_tables(void) { char *ext= fn_ext(file->name); size_t ext_len= strlen(ext); - size_t filePath_len= my_snprintf(filePath, sizeof(filePath), + size_t path_len= my_snprintf(path, sizeof(path), "%s%c%s", tmpdir, FN_LIBCHAR, file->name); if (!strcmp(reg_ext, ext)) { - handler *handler_file= 0; /* We should cut file extention before deleting of table */ - memcpy(filePathCopy, filePath, filePath_len - ext_len); - filePathCopy[filePath_len - ext_len]= 0; - init_tmp_table_share(thd, &share, "", 0, "", filePathCopy); - if (!open_table_def(thd, &share) && - ((handler_file= get_new_handler(&share, thd->mem_root, - share.db_type())))) - { - handler_file->ha_delete_table(filePathCopy); - delete handler_file; - } + memcpy(path_copy, path, path_len - ext_len); + path_copy[path_len - ext_len]= 0; + init_tmp_table_share(thd, &share, "", 0, "", path_copy); + if (!open_table_def(thd, &share)) + share.db_type()->drop_table(share.db_type(), path_copy); free_table_share(&share); } /* @@ -8990,7 +8914,7 @@ my_bool mysql_rm_tmp_tables(void) So we hide error messages which happnes during deleting of these files(MYF(0)). */ - (void) mysql_file_delete(key_file_misc, filePath, MYF(0)); + (void) mysql_file_delete(key_file_misc, path, MYF(0)); } } my_dirend(dirp); @@ -9072,17 +8996,16 @@ bool is_equal(const LEX_CSTRING *a, const LEX_CSTRING *b) open_system_tables_for_read() thd Thread context. table_list List of tables to open. - backup Pointer to Open_tables_state instance where - information about currently open tables will be - saved, and from which will be restored when we will - end work with system tables. NOTES + Caller should have used start_new_trans object to start a new + transcation when reading system tables. + Thanks to restrictions which we put on opening and locking of system tables for writing, we can open and lock them for reading - even when we already have some other tables open and locked. One - must call close_system_tables() to close systems tables opened - with this call. + even when we already have some other tables open and locked. + One should call thd->commit_whole_transaction_and_close_tables() + to close systems tables opened with this call. NOTES In some situations we use this function to open system tables for @@ -9096,22 +9019,20 @@ bool is_equal(const LEX_CSTRING *a, const LEX_CSTRING *b) */ bool -open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, - Open_tables_backup *backup) +open_system_tables_for_read(THD *thd, TABLE_LIST *table_list) { Query_tables_list query_tables_list_backup; LEX *lex= thd->lex; DBUG_ENTER("open_system_tables_for_read"); + DBUG_ASSERT(thd->internal_transaction()); /* Besides using new Open_tables_state for opening system tables, we also have to backup and reset/and then restore part of LEX which is accessed by open_tables() in order to determine if prelocking is needed and what tables should be added for it. - close_system_tables() doesn't require such treatment. */ lex->reset_n_backup_query_tables_list(&query_tables_list_backup); - thd->reset_n_backup_open_tables_state(backup); thd->lex->sql_command= SQLCOM_SELECT; /* @@ -9121,17 +9042,18 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, */ if (open_and_lock_tables(thd, table_list, FALSE, (MYSQL_OPEN_IGNORE_FLUSH | + MYSQL_OPEN_IGNORE_LOGGING_FORMAT | (table_list->lock_type < TL_WRITE_ALLOW_WRITE ? MYSQL_LOCK_IGNORE_TIMEOUT : 0)))) { lex->restore_backup_query_tables_list(&query_tables_list_backup); - thd->restore_backup_open_tables_state(backup); DBUG_RETURN(TRUE); } for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global) { DBUG_ASSERT(tables->table->s->table_category == TABLE_CATEGORY_SYSTEM); + tables->table->file->row_logging= 0; tables->table->use_all_columns(); } lex->restore_backup_query_tables_list(&query_tables_list_backup); @@ -9139,33 +9061,6 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(FALSE); } - -/* - Close system tables, opened with open_system_tables_for_read(). - - SYNOPSIS - close_system_tables() - thd Thread context - backup Pointer to Open_tables_backup instance which holds - information about tables which were open before we - decided to access system tables. -*/ - -void -close_system_tables(THD *thd, Open_tables_backup *backup) -{ - /* - Inform the transaction handler that we are closing the - system tables and we don't need the read view anymore. - */ - for (TABLE *table= thd->open_tables ; table ; table= table->next) - table->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE); - - close_thread_tables(thd); - thd->restore_backup_open_tables_state(backup); -} - - /** A helper function to close a mysql.* table opened in an auxiliary THD during bootstrap or in the main @@ -9187,7 +9082,10 @@ void close_mysql_tables(THD *thd) { if (! thd->in_sub_stmt) + { trans_commit_stmt(thd); + trans_commit(thd); + } close_thread_tables(thd); thd->release_transactional_locks(); } @@ -9219,8 +9117,9 @@ open_system_table_for_update(THD *thd, TABLE_LIST *one_table) { DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM); table->use_all_columns(); + /* This table instance is not row logged */ + table->file->row_logging= 0; } - DBUG_RETURN(table); } @@ -9253,6 +9152,8 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup) if ((table= open_ltable(thd, one_table, one_table->lock_type, flags))) { DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_LOG); + DBUG_ASSERT(!table->file->row_logging); + /* Make sure all columns get assigned to a default value */ table->use_all_columns(); DBUG_ASSERT(table->s->no_replicate); @@ -9271,9 +9172,17 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup) @param thd The current thread @param backup [in] the context to restore. */ + void close_log_table(THD *thd, Open_tables_backup *backup) { - close_system_tables(thd, backup); + /* + Inform the transaction handler that we are closing the + system tables and we don't need the read view anymore. + */ + for (TABLE *table= thd->open_tables ; table ; table= table->next) + table->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE); + close_thread_tables(thd); + thd->restore_backup_open_tables_state(backup); } |