summaryrefslogtreecommitdiff
path: root/sql/sql_base.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r--sql/sql_base.cc437
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;