diff options
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 437 |
1 files changed, 255 insertions, 182 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7116d046a8c..7e0d17d1b0e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,7 +21,7 @@ #include "sql_priv.h" #include "unireg.h" #include "debug_sync.h" -#include "lock.h" // broadcast_refresh, mysql_lock_remove, +#include "lock.h" // mysql_lock_remove, // mysql_unlock_tables, // mysql_lock_have_duplicate #include "sql_show.h" // append_identifier @@ -101,14 +101,11 @@ bool No_such_table_error_handler::safely_trapped_errors() TABLE_SHAREs, refresh_version and the table id counter. */ mysql_mutex_t LOCK_open; -mysql_mutex_t LOCK_dd_owns_lock_open; -uint dd_owns_lock_open= 0; #ifdef HAVE_PSI_INTERFACE -static PSI_mutex_key key_LOCK_open, key_LOCK_dd_owns_lock_open; +static PSI_mutex_key key_LOCK_open; static PSI_mutex_info all_tdc_mutexes[]= { - { &key_LOCK_open, "LOCK_open", PSI_FLAG_GLOBAL }, - { &key_LOCK_dd_owns_lock_open, "LOCK_dd_owns_lock_open", PSI_FLAG_GLOBAL } + { &key_LOCK_open, "LOCK_open", PSI_FLAG_GLOBAL } }; /** @@ -251,7 +248,8 @@ static void check_unused(void) Length of key */ -uint create_table_def_key(THD *thd, char *key, TABLE_LIST *table_list, +uint create_table_def_key(THD *thd, char *key, + const TABLE_LIST *table_list, bool tmp_table) { char *db_end= strnmov(key, table_list->db, MAX_DBKEY_LENGTH - 2); @@ -306,8 +304,6 @@ bool table_def_init(void) init_tdc_psi_keys(); #endif mysql_mutex_init(key_LOCK_open, &LOCK_open, MY_MUTEX_INIT_FAST); - mysql_mutex_init(key_LOCK_dd_owns_lock_open, &LOCK_dd_owns_lock_open, - MY_MUTEX_INIT_FAST); oldest_unused_share= &end_of_unused_share; end_of_unused_share.prev= &oldest_unused_share; @@ -351,7 +347,6 @@ void table_def_free(void) table_def_inited= 0; /* Free table definitions. */ my_hash_free(&table_def_cache); - mysql_mutex_destroy(&LOCK_dd_owns_lock_open); mysql_mutex_destroy(&LOCK_open); } DBUG_VOID_RETURN; @@ -1036,7 +1031,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, table_list= table_list->next_global) { /* A check that the table was locked for write is done by the caller. */ - TABLE *table= find_table_for_mdl_upgrade(thd->open_tables, table_list->db, + TABLE *table= find_table_for_mdl_upgrade(thd, table_list->db, table_list->table_name, TRUE); /* May return NULL if this table has already been closed via an alias. */ @@ -1295,20 +1290,12 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table) static void close_open_tables(THD *thd) { - bool found_old_table= 0; - mysql_mutex_assert_not_owner(&LOCK_open); DBUG_PRINT("info", ("thd->open_tables: 0x%lx", (long) thd->open_tables)); while (thd->open_tables) - found_old_table|= close_thread_table(thd, &thd->open_tables); - - if (found_old_table) - { - /* Tell threads waiting for refresh that something has happened */ - broadcast_refresh(); - } + (void) close_thread_table(thd, &thd->open_tables); } @@ -1376,11 +1363,6 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share, /* Remove the table share from the cache. */ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db, table_name, FALSE); - /* - There could be a FLUSH thread waiting - on the table to go away. Wake it up. - */ - broadcast_refresh(); } @@ -2014,39 +1996,60 @@ void update_non_unique_table_error(TABLE_LIST *update, } +/** + Find temporary table specified by database and table names in the + THD::temporary_tables list. + + @return TABLE instance if a temporary table has been found; NULL otherwise. +*/ + TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name) { - TABLE_LIST table_list; + TABLE_LIST tl; - table_list.db= (char*) db; - table_list.table_name= (char*) table_name; - return find_temporary_table(thd, &table_list); + tl.db= (char*) db; + tl.table_name= (char*) table_name; + + return find_temporary_table(thd, &tl); } -TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list) +/** + Find a temporary table specified by TABLE_LIST instance in the + THD::temporary_tables list. + + @return TABLE instance if a temporary table has been found; NULL otherwise. +*/ + +TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl) { - char key[MAX_DBKEY_LENGTH]; - uint key_length; - TABLE *table; - DBUG_ENTER("find_temporary_table"); - DBUG_PRINT("enter", ("table: '%s'.'%s'", - table_list->db, table_list->table_name)); + char key[MAX_DBKEY_LENGTH]; + uint key_length= create_table_def_key(thd, key, tl, 1); - key_length= create_table_def_key(thd, key, table_list, 1); - for (table=thd->temporary_tables ; table ; table= table->next) + return find_temporary_table(thd, key, key_length); +} + + +/** + Find a temporary table specified by a key in the THD::temporary_tables list. + + @return TABLE instance if a temporary table has been found; NULL otherwise. +*/ + +TABLE *find_temporary_table(THD *thd, + const char *table_key, + uint table_key_length) +{ + for (TABLE *table= thd->temporary_tables; table; table= table->next) { - if (table->s->table_cache_key.length == key_length && - !memcmp(table->s->table_cache_key.str, key, key_length)) + if (table->s->table_cache_key.length == table_key_length && + !memcmp(table->s->table_cache_key.str, table_key, table_key_length)) { - DBUG_PRINT("info", - ("Found table. server_id: %u pseudo_thread_id: %lu", - (uint) thd->server_id, - (ulong) thd->variables.pseudo_thread_id)); - DBUG_RETURN(table); + return table; } } - DBUG_RETURN(0); // Not a temporary table + + return NULL; } @@ -2474,7 +2477,8 @@ open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx, mdl_request_shared.init(&mdl_request->key, (flags & MYSQL_OPEN_FORCE_SHARED_MDL) ? - MDL_SHARED : MDL_SHARED_HIGH_PRIO); + MDL_SHARED : MDL_SHARED_HIGH_PRIO, + MDL_TRANSACTION); mdl_request= &mdl_request_shared; } @@ -2639,32 +2643,6 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, TMP_TABLE_KEY_EXTRA); /* - We need this to work for all tables, including temporary - tables, for backwards compatibility. But not under LOCK - TABLES, since under LOCK TABLES one can't use a non-prelocked - table. This code only works for updates done inside DO/SELECT - f1() statements, normal DML is handled by means of - sql_command_flags. - */ - if (global_read_lock && table_list->lock_type >= TL_WRITE_ALLOW_WRITE && - ! (flags & MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK) && - ! thd->locked_tables_mode) - { - /* - Someone has issued FLUSH TABLES WITH READ LOCK and we want - a write lock. Wait until the lock is gone. - */ - if (thd->global_read_lock.wait_if_global_read_lock(thd, 1, 1)) - DBUG_RETURN(TRUE); - - if (thd->open_tables && thd->open_tables->s->version != refresh_version) - { - (void)ot_ctx->request_backoff_action(Open_table_context::OT_REOPEN_TABLES, - NULL); - DBUG_RETURN(TRUE); - } - } - /* Unless requested otherwise, try to resolve this table in the list of temporary tables of this thread. In MySQL temporary tables are always thread-local and "shadow" possible base tables with the @@ -2835,6 +2813,59 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK)) { + /* + We are not under LOCK TABLES and going to acquire write-lock/ + modify the base table. We need to acquire protection against + global read lock until end of this statement in order to have + this statement blocked by active FLUSH TABLES WITH READ LOCK. + + We don't block acquire this protection under LOCK TABLES as + such protection already acquired at LOCK TABLES time and + not released until UNLOCK TABLES. + + We don't block statements which modify only temporary tables + as these tables are not preserved by backup by any form of + backup which uses FLUSH TABLES WITH READ LOCK. + + TODO: The fact that we sometimes acquire protection against + GRL only when we encounter table to be write-locked + slightly increases probability of deadlock. + This problem will be solved once Alik pushes his + temporary table refactoring patch and we can start + pre-acquiring metadata locks at the beggining of + open_tables() call. + */ + if (table_list->mdl_request.type >= MDL_SHARED_WRITE && + ! (flags & (MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK | + MYSQL_OPEN_FORCE_SHARED_MDL | + MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL | + MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) && + ! ot_ctx->has_protection_against_grl()) + { + MDL_request protection_request; + MDL_deadlock_handler mdl_deadlock_handler(ot_ctx); + + if (thd->global_read_lock.can_acquire_protection()) + DBUG_RETURN(TRUE); + + protection_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE, + MDL_STATEMENT); + + /* + Install error handler which if possible will convert deadlock error + into request to back-off and restart process of opening tables. + */ + thd->push_internal_handler(&mdl_deadlock_handler); + bool result= thd->mdl_context.acquire_lock(&protection_request, + ot_ctx->get_timeout()); + thd->pop_internal_handler(); + + if (result) + DBUG_RETURN(TRUE); + + ot_ctx->set_has_protection_against_grl(); + } + if (open_table_get_mdl_lock(thd, ot_ctx, &table_list->mdl_request, flags, &mdl_ticket) || mdl_ticket == NULL) @@ -2913,8 +2944,12 @@ retry_share: */ if (check_and_update_table_version(thd, table_list, share)) goto err_unlock; - if (table_list->i_s_requested_object & OPEN_TABLE_ONLY) + if (table_list->i_s_requested_object & OPEN_TABLE_ONLY) + { + my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, + table_list->table_name); goto err_unlock; + } /* Open view */ if (open_new_frm(thd, share, alias, @@ -2942,7 +2977,11 @@ retry_share: */ if (table_list->i_s_requested_object & OPEN_VIEW_ONLY) + { + my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, + table_list->table_name); goto err_unlock; + } if (!(flags & MYSQL_OPEN_IGNORE_FLUSH)) { @@ -3056,47 +3095,16 @@ retry_share: table->reginfo.lock_type=TL_READ; /* Assume read */ reset: - DBUG_ASSERT(table->s->ref_count > 0 || table->s->tmp_table != NO_TMP_TABLE); - - if (thd->lex->need_correct_ident()) - table->alias_name_used= my_strcasecmp(table_alias_charset, - table->s->table_name.str, alias); - /* Fix alias if table name changes */ - if (strcmp(table->alias, alias)) - { - uint length=(uint) strlen(alias)+1; - table->alias= (char*) my_realloc((char*) table->alias, length, - MYF(MY_WME)); - memcpy((char*) table->alias, alias, length); - } - table->tablenr=thd->current_tablenr++; - table->used_fields=0; - table->const_table=0; - table->null_row= 0; - table->maybe_null= 0; - table->force_index= table->force_index_order= table->force_index_group= 0; - table->status=STATUS_NO_RECORD; - table->insert_values= 0; - table->fulltext_searched= 0; - table->file->ha_start_of_new_statement(); - table->reginfo.impossible_range= 0; - /* Catch wrong handling of the auto_increment_field_not_null. */ - DBUG_ASSERT(!table->auto_increment_field_not_null); - table->auto_increment_field_not_null= FALSE; - if (table->timestamp_field) - table->timestamp_field_type= table->timestamp_field->get_auto_set_type(); - table->pos_in_table_list= table_list; - table_list->updatable= 1; // It is not derived table nor non-updatable VIEW - table->clear_column_bitmaps(); - table_list->table= table; /* - Fill record with random values to find bugs where we access fields - without first reading them. + Check that there is no reference to a condition from an earlier query + (cf. Bug#58553). */ - TRASH(table->record[0], table->s->reclength); - DBUG_ASSERT(table->key_read == 0); - /* Tables may be reused in a sub statement. */ - DBUG_ASSERT(! table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN)); + DBUG_ASSERT(table->file->pushed_cond == NULL); + table_list->updatable= 1; // It is not derived table nor non-updatable VIEW + table_list->table= table; + + table->init(thd, table_list); + DBUG_RETURN(FALSE); err_lock: @@ -3139,22 +3147,26 @@ TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name) lock from the list of open tables, emit error if no such table found. - @param list List of TABLE objects to be searched + @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. + @note This function checks if the connection holds a global IX + metadata lock. If no such lock is found, it is not safe to + upgrade the lock and ER_TABLE_NOT_LOCKED_FOR_WRITE will be + reported. + @return Pointer to TABLE instance with MDL_SHARED_NO_WRITE, MDL_SHARED_NO_READ_WRITE, or MDL_EXCLUSIVE metadata lock, NULL otherwise. */ -TABLE *find_table_for_mdl_upgrade(TABLE *list, const char *db, - const char *table_name, - bool no_error) +TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db, + const char *table_name, bool no_error) { - TABLE *tab= find_locked_table(list, db, table_name); + TABLE *tab= find_locked_table(thd->open_tables, db, table_name); if (!tab) { @@ -3162,19 +3174,29 @@ TABLE *find_table_for_mdl_upgrade(TABLE *list, const char *db, my_error(ER_TABLE_NOT_LOCKED, MYF(0), table_name); return NULL; } - else + + /* + It is not safe to upgrade the metadata lock without a global IX lock. + This can happen with FLUSH TABLES <list> WITH READ LOCK as we in these + cases don't take a global IX lock in order to be compatible with + global read lock. + */ + if (!thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "", + MDL_INTENTION_EXCLUSIVE)) { - while (tab->mdl_ticket != NULL && - !tab->mdl_ticket->is_upgradable_or_exclusive() && - (tab= find_locked_table(tab->next, db, table_name))) - continue; - if (!tab) - { - if (!no_error) - my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name); - return 0; - } + if (!no_error) + my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name); + return NULL; } + + while (tab->mdl_ticket != NULL && + !tab->mdl_ticket->is_upgradable_or_exclusive() && + (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); + return tab; } @@ -3418,7 +3440,6 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count) close_thread_table(thd, &thd->open_tables); } - broadcast_refresh(); } /* Exclude all closed tables from the LOCK TABLES list. */ for (TABLE_LIST *table_list= m_locked_tables; table_list; table_list= @@ -3860,7 +3881,7 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list) { /* Give right error message */ thd->clear_error(); - my_error(ER_NOT_KEYFILE, MYF(0), share->table_name.str, my_errno); + 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) @@ -3895,7 +3916,8 @@ Open_table_context::Open_table_context(THD *thd, uint flags) LONG_TIMEOUT : thd->variables.lock_wait_timeout), m_flags(flags), m_action(OT_NO_ACTION), - m_has_locks(thd->mdl_context.has_locks()) + m_has_locks(thd->mdl_context.has_locks()), + m_has_protection_against_grl(FALSE) {} @@ -4052,6 +4074,12 @@ recover_from_failed_open(THD *thd) for safety. */ m_failed_table= NULL; + /* + Reset flag indicating that we have already acquired protection + against GRL. It is no longer valid as the corresponding lock was + released by close_tables_for_reopen(). + */ + m_has_protection_against_grl= FALSE; /* Prepare for possible another back-off. */ m_action= OT_NO_ACTION; return result; @@ -4569,13 +4597,15 @@ lock_table_names(THD *thd, ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) && find_temporary_table(thd, table)))) { - if (schema_set.insert(table)) + if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) && + schema_set.insert(table)) return TRUE; mdl_requests.push_front(&table->mdl_request); } } - if (! mdl_requests.is_empty()) + if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) && + ! mdl_requests.is_empty()) { /* Scoped locks: Take intention exclusive locks on all involved @@ -4588,11 +4618,20 @@ lock_table_names(THD *thd, if (schema_request == NULL) return TRUE; schema_request->init(MDL_key::SCHEMA, table->db, "", - MDL_INTENTION_EXCLUSIVE); + MDL_INTENTION_EXCLUSIVE, + MDL_TRANSACTION); mdl_requests.push_front(schema_request); } - /* Take the global intention exclusive lock. */ - global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE); + + /* + Protect this statement against concurrent global read lock + by acquiring global intention exclusive lock with statement + duration. + */ + if (thd->global_read_lock.can_acquire_protection()) + return TRUE; + global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE, + MDL_STATEMENT); mdl_requests.push_front(&global_request); } @@ -4655,8 +4694,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->open_tables, table->db, - table->table_name, FALSE)) + if (!find_table_for_mdl_upgrade(thd, table->db, table->table_name, false)) return TRUE; } } @@ -4713,6 +4751,14 @@ bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags, bool has_prelocking_list; DBUG_ENTER("open_tables"); + /* Accessing data in XA_IDLE or XA_PREPARED is not allowed. */ + enum xa_states xa_state= thd->transaction.xid_state.xa_state; + if (*start && (xa_state == XA_IDLE || xa_state == XA_PREPARED)) + { + my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]); + DBUG_RETURN(true); + } + /* temporary mem_root for new .frm parsing. TODO: variables for size @@ -5210,6 +5256,8 @@ static bool check_lock_and_start_stmt(THD *thd, @param[in] lock_type lock to use for table @param[in] flags options to be used while opening and locking table (see open_table(), mysql_lock_tables()) + @param[in] prelocking_strategy Strategy which specifies how prelocking + algorithm should work for this statement. @return table @retval != NULL OK, opened table returned @@ -5235,7 +5283,8 @@ static bool check_lock_and_start_stmt(THD *thd, */ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, - thr_lock_type lock_type, uint flags) + thr_lock_type lock_type, uint flags, + Prelocking_strategy *prelocking_strategy) { TABLE_LIST *save_next_global; DBUG_ENTER("open_n_lock_single_table"); @@ -5251,7 +5300,8 @@ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, table_l->required_type= FRMTYPE_TABLE; /* Open the table. */ - if (open_and_lock_tables(thd, table_l, FALSE, flags)) + if (open_and_lock_tables(thd, table_l, FALSE, flags, + prelocking_strategy)) table_l->table= NULL; /* Just to be sure. */ /* Restore list. */ @@ -5360,7 +5410,11 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type, end: if (table == NULL) + { + if (!thd->in_sub_stmt) + trans_rollback_stmt(thd); close_thread_tables(thd); + } thd_proc_info(thd, 0); DBUG_RETURN(table); } @@ -5391,7 +5445,7 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, Prelocking_strategy *prelocking_strategy) { uint counter; - MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); + MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); DBUG_ENTER("open_and_lock_tables"); DBUG_PRINT("enter", ("derived handling: %d", derived)); @@ -5407,11 +5461,19 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, if (lock_tables(thd, tables, counter, flags)) goto err; - if (derived && - (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || - (thd->fill_derived_tables() && - mysql_handle_derived(thd->lex, &mysql_derived_filling)))) - goto err; + if (derived) + { + if (mysql_handle_derived(thd->lex, &mysql_derived_prepare)) + goto err; + if (thd->fill_derived_tables() && + mysql_handle_derived(thd->lex, &mysql_derived_filling)) + { + mysql_handle_derived(thd->lex, &mysql_derived_cleanup); + goto err; + } + if (!thd->lex->describe) + mysql_handle_derived(thd->lex, &mysql_derived_cleanup); + } DBUG_RETURN(FALSE); err: @@ -5448,7 +5510,7 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags) { DML_prelocking_strategy prelocking_strategy; uint counter; - MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); + MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); DBUG_ENTER("open_normal_and_derived_tables"); DBUG_ASSERT(!thd->fill_derived_tables()); if (open_tables(thd, &tables, &counter, flags, &prelocking_strategy) || @@ -5705,7 +5767,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, */ void close_tables_for_reopen(THD *thd, TABLE_LIST **tables, - MDL_ticket *start_of_statement_svp) + const MDL_savepoint &start_of_statement_svp) { TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); TABLE_LIST *tmp; @@ -5743,35 +5805,37 @@ void close_tables_for_reopen(THD *thd, TABLE_LIST **tables, } -/* - Open a single table without table caching and don't set it in open_list - - SYNPOSIS - open_temporary_table() - thd Thread object - path Path (without .frm) - db database - table_name Table name - link_in_list 1 if table should be linked into thd->temporary_tables - - NOTES: - Used by alter_table to open a temporary table and when creating - a temporary table with CREATE TEMPORARY ... - - RETURN - 0 Error - # TABLE object +/** + Open a single table without table caching and don't add it to + THD::open_tables. Depending on the 'add_to_temporary_tables_list' value, + the opened TABLE instance will be addded to THD::temporary_tables list. + + @param thd Thread context. + @param path Path (without .frm) + @param db Database name. + @param table_name Table name. + @param add_to_temporary_tables_list Specifies if the opened TABLE + instance should be linked into + THD::temporary_tables list. + + @note This function is used: + - by alter_table() to open a temporary table; + - when creating a temporary table with CREATE TEMPORARY TABLE. + + @return TABLE instance for opened table. + @retval NULL on error. */ -TABLE *open_temporary_table(THD *thd, const char *path, const char *db, - const char *table_name, bool link_in_list) +TABLE *open_table_uncached(THD *thd, const char *path, const char *db, + const char *table_name, + bool add_to_temporary_tables_list) { TABLE *tmp_table; TABLE_SHARE *share; char cache_key[MAX_DBKEY_LENGTH], *saved_cache_key, *tmp_path; uint key_length; TABLE_LIST table_list; - DBUG_ENTER("open_temporary_table"); + DBUG_ENTER("open_table_uncached"); DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s' server_id: %u " "pseudo_thread_id: %lu", @@ -5814,7 +5878,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, share->tmp_table= (tmp_table->file->has_transactions() ? TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE); - if (link_in_list) + if (add_to_temporary_tables_list) { /* growing temp list at the head */ tmp_table->next= thd->temporary_tables; @@ -6144,6 +6208,8 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, /* Find field by name in a base table or a view with temp table algorithm. + The caller is expected to check column-level privileges. + SYNOPSIS find_field_in_table() thd thread handler @@ -6251,6 +6317,8 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, This procedure detects the type of the table reference 'table_list' and calls the corresponding search routine. + The routine checks column-level privieleges for the found field. + RETURN 0 field is not found view_ref_found found value in VIEW (real result is in *ref) @@ -6526,8 +6594,16 @@ find_field_in_tables(THD *thd, Item_ident *item, when table_ref->field_translation != NULL. */ if (table_ref->table && !table_ref->view) + { found= find_field_in_table(thd, table_ref->table, name, length, TRUE, &(item->cached_field_index)); +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* Check if there are sufficient access rights to the found field. */ + if (found && check_privileges && + check_column_grant_in_table_ref(thd, table_ref, name, length)) + found= WRONG_GRANT; +#endif + } else found= find_field_in_table_ref(thd, table_ref, name, length, item->name, NULL, NULL, ref, check_privileges, @@ -7567,9 +7643,10 @@ static bool setup_natural_join_row_types(THD *thd, List<TABLE_LIST> *from_clause, Name_resolution_context *context) { + DBUG_ENTER("setup_natural_join_row_types"); thd->where= "from clause"; if (from_clause->elements == 0) - return FALSE; /* We come here in the case of UNIONs. */ + DBUG_RETURN(false); /* We come here in the case of UNIONs. */ List_iterator_fast<TABLE_LIST> table_ref_it(*from_clause); TABLE_LIST *table_ref; /* Current table reference. */ @@ -7577,10 +7654,6 @@ static bool setup_natural_join_row_types(THD *thd, TABLE_LIST *left_neighbor; /* Table reference to the right of the current. */ TABLE_LIST *right_neighbor= NULL; - bool save_first_natural_join_processing= - context->select_lex->first_natural_join_processing; - - context->select_lex->first_natural_join_processing= FALSE; /* Note that tables in the list are in reversed order */ for (left_neighbor= table_ref_it++; left_neighbor ; ) @@ -7592,12 +7665,11 @@ static bool setup_natural_join_row_types(THD *thd, 1) for stored procedures, 2) for multitable update after lock failure and table reopening. */ - if (save_first_natural_join_processing) + if (context->select_lex->first_natural_join_processing) { - context->select_lex->first_natural_join_processing= FALSE; if (store_top_level_join_columns(thd, table_ref, left_neighbor, right_neighbor)) - return TRUE; + DBUG_RETURN(true); if (left_neighbor) { TABLE_LIST *first_leaf_on_the_right; @@ -7617,8 +7689,9 @@ static bool setup_natural_join_row_types(THD *thd, DBUG_ASSERT(right_neighbor); context->first_name_resolution_table= right_neighbor->first_leaf_for_name_resolution(); + context->select_lex->first_natural_join_processing= false; - return FALSE; + DBUG_RETURN (false); } @@ -7892,7 +7965,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, } if (tablenr > MAX_TABLES) { - my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES); + my_error(ER_TOO_MANY_TABLES,MYF(0), static_cast<int>(MAX_TABLES)); DBUG_RETURN(1); } for (table_list= tables; |