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.cc1551
1 files changed, 372 insertions, 1179 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1dbed8c55d1..f31c3f36aa8 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -49,6 +49,7 @@
#include "transaction.h"
#include "sql_prepare.h"
#include "sql_statistics.h"
+#include "sql_cte.h"
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
@@ -67,7 +68,7 @@ bool
No_such_table_error_handler::handle_condition(THD *,
uint sql_errno,
const char*,
- Sql_condition::enum_warning_level level,
+ Sql_condition::enum_warning_level *level,
const char*,
Sql_condition ** cond_hdl)
{
@@ -78,7 +79,7 @@ No_such_table_error_handler::handle_condition(THD *,
return TRUE;
}
- if (level == Sql_condition::WARN_LEVEL_ERROR)
+ if (*level == Sql_condition::WARN_LEVEL_ERROR)
m_unhandled_errors++;
return FALSE;
}
@@ -111,7 +112,7 @@ public:
bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
- Sql_condition::enum_warning_level level,
+ Sql_condition::enum_warning_level *level,
const char* msg,
Sql_condition ** cond_hdl);
@@ -141,7 +142,7 @@ bool
Repair_mrg_table_error_handler::handle_condition(THD *,
uint sql_errno,
const char*,
- Sql_condition::enum_warning_level level,
+ Sql_condition::enum_warning_level *level,
const char*,
Sql_condition ** cond_hdl)
{
@@ -171,47 +172,13 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list);
/**
- Create a table cache/table definition cache key
-
- @param thd Thread context
- @param key Buffer for the key to be created (must be of
- size MAX_DBKEY_LENGTH).
- @param db_name Database name.
- @param table_name Table name.
-
- @note
- The table cache_key is created from:
- db_name + \0
- table_name + \0
-
- additionally we add the following to make each tmp table
- unique on the slave:
-
- 4 bytes for master thread id
- 4 bytes pseudo thread id
-
- @return Length of key.
-*/
-
-uint create_tmp_table_def_key(THD *thd, char *key,
- const char *db, const char *table_name)
-{
- uint key_length= tdc_create_key(key, db, table_name);
- int4store(key + key_length, thd->variables.server_id);
- int4store(key + key_length + 4, thd->variables.pseudo_thread_id);
- key_length+= TMP_TABLE_KEY_EXTRA;
- return key_length;
-}
-
-
-/**
Get table cache key for a table list element.
@param table_list[in] Table list element.
@param key[out] On return points to table cache key for the table.
@note Unlike create_table_def_key() call this function doesn't construct
- key in a buffer provider by caller. Instead it relies on the fact
+ key in a buffer provided by caller. Instead it relies on the fact
that table list element for which key is requested has properly
initialized MDL_request object and the fact that table definition
cache key is suffix of key used in MDL subsystem. So to get table
@@ -303,7 +270,7 @@ static my_bool list_open_tables_callback(TDC_element *element,
(*arg->start_list)->in_use= 0;
mysql_mutex_lock(&element->LOCK_table_share);
- TDC_element::All_share_tables_list::Iterator it(element->all_tables);
+ All_share_tables_list::Iterator it(element->all_tables);
TABLE *table;
while ((table= it++))
if (table->in_use)
@@ -335,84 +302,6 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild)
DBUG_RETURN(argument.open_list);
}
-/*****************************************************************************
- * Functions to free open table cache
- ****************************************************************************/
-
-
-void intern_close_table(TABLE *table)
-{ // Free all structures
- DBUG_ENTER("intern_close_table");
- DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx",
- table->s ? table->s->db.str : "?",
- table->s ? table->s->table_name.str : "?",
- (long) table));
-
- free_io_cache(table);
- delete table->triggers;
- if (table->file) // Not true if placeholder
- (void) closefrm(table, 1); // close file
- table->alias.free();
- my_free(table);
- DBUG_VOID_RETURN;
-}
-
-
-/* Free resources allocated by filesort() and read_record() */
-
-void free_io_cache(TABLE *table)
-{
- DBUG_ENTER("free_io_cache");
- if (table->sort.io_cache)
- {
- close_cached_file(table->sort.io_cache);
- my_free(table->sort.io_cache);
- table->sort.io_cache=0;
- }
- DBUG_VOID_RETURN;
-}
-
-
-/**
- Auxiliary function which allows to kill delayed threads for
- particular table identified by its share.
-
- @param share Table share.
-
- @pre Caller should have TABLE_SHARE::tdc.LOCK_table_share mutex.
-*/
-
-void kill_delayed_threads_for_table(TDC_element *element)
-{
- TDC_element::All_share_tables_list::Iterator it(element->all_tables);
- TABLE *tab;
-
- mysql_mutex_assert_owner(&element->LOCK_table_share);
-
- if (!delayed_insert_threads)
- return;
-
- while ((tab= it++))
- {
- THD *in_use= tab->in_use;
-
- DBUG_ASSERT(in_use && tab->s->tdc->flushed);
- if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
- ! in_use->killed)
- {
- in_use->set_killed(KILL_SYSTEM_THREAD);
- mysql_mutex_lock(&in_use->mysys_var->mutex);
- if (in_use->mysys_var->current_cond)
- {
- mysql_mutex_lock(in_use->mysys_var->current_mutex);
- mysql_cond_broadcast(in_use->mysys_var->current_cond);
- mysql_mutex_unlock(in_use->mysys_var->current_mutex);
- }
- mysql_mutex_unlock(&in_use->mysys_var->mutex);
- }
- }
-}
-
/*
Close all tables which aren't in use by any thread
@@ -436,7 +325,7 @@ void kill_delayed_threads_for_table(TDC_element *element)
struct close_cached_tables_arg
{
- ulong refresh_version;
+ tdc_version_t refresh_version;
TDC_element *element;
};
@@ -462,7 +351,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
{
bool result= FALSE;
struct timespec abstime;
- ulong refresh_version;
+ tdc_version_t refresh_version;
DBUG_ENTER("close_cached_tables");
DBUG_ASSERT(thd || (!wait_for_refresh && !tables));
@@ -593,7 +482,8 @@ err_with_reopen:
old locks. This should always succeed (unless some external process
has removed the tables)
*/
- thd->locked_tables_list.reopen_tables(thd, false);
+ if (thd->locked_tables_list.reopen_tables(thd, false))
+ result= true;
/*
Since downgrade_lock() won't do anything with shared
metadata lock it is much simpler to go through all open tables rather
@@ -680,85 +570,6 @@ bool close_cached_connection_tables(THD *thd, LEX_STRING *connection)
}
-/**
- Mark all temporary tables which were used by the current statement or
- substatement as free for reuse, but only if the query_id can be cleared.
-
- @param thd thread context
-
- @remark For temp tables associated with a open SQL HANDLER the query_id
- is not reset until the HANDLER is closed.
-*/
-
-static void mark_temp_tables_as_free_for_reuse(THD *thd)
-{
- DBUG_ENTER("mark_temp_tables_as_free_for_reuse");
-
- if (thd->query_id == 0)
- {
- /* Thread has not executed any statement and has not used any tmp tables */
- DBUG_VOID_RETURN;
- }
-
- if (thd->have_temporary_tables())
- {
- thd->lock_temporary_tables();
- for (TABLE *table= thd->temporary_tables ; table ; table= table->next)
- {
- if ((table->query_id == thd->query_id) && ! table->open_by_handler)
- mark_tmp_table_for_reuse(table);
- }
- thd->unlock_temporary_tables(1);
- }
- DBUG_VOID_RETURN;
-}
-
-
-/**
- Reset a single temporary table.
- Effectively this "closes" one temporary table,
- in a session.
-
- @param table Temporary table.
-*/
-
-void mark_tmp_table_for_reuse(TABLE *table)
-{
- DBUG_ENTER("mark_tmp_table_for_reuse");
- DBUG_ASSERT(table->s->tmp_table);
-
- table->query_id= 0;
- table->file->ha_reset();
-
- /* Detach temporary MERGE children from temporary parent. */
- DBUG_ASSERT(table->file);
- table->file->extra(HA_EXTRA_DETACH_CHILDREN);
-
- /*
- Reset temporary table lock type to it's default value (TL_WRITE).
-
- Statements such as INSERT INTO .. SELECT FROM tmp, CREATE TABLE
- .. SELECT FROM tmp and UPDATE may under some circumstances modify
- the lock type of the tables participating in the statement. This
- isn't a problem for non-temporary tables since their lock type is
- reset at every open, but the same does not occur for temporary
- tables for historical reasons.
-
- Furthermore, the lock type of temporary tables is not really that
- important because they can only be used by one query at a time and
- not even twice in a query -- a temporary table is represented by
- only one TABLE object. Nonetheless, it's safer from a maintenance
- point of view to reset the lock type of this singleton TABLE object
- as to not cause problems when the table is reused.
-
- Even under LOCK TABLES mode its okay to reset the lock type as
- LOCK TABLES is allowed (but ignored) for a temporary table.
- */
- table->reginfo.lock_type= TL_WRITE;
- DBUG_VOID_RETURN;
-}
-
-
/*
Mark all tables in the list which were used by current substatement
as free for reuse.
@@ -772,6 +583,12 @@ void mark_tmp_table_for_reuse(TABLE *table)
Marks all tables in the list which were used by current substatement
(they are marked by its query_id) as free for reuse.
+ 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.
+
NOTE
The reason we reset query_id is that it's not enough to just test
if table->query_id != thd->query_id to know if a table is in use.
@@ -793,28 +610,13 @@ 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)
+ table->file->clear_cached_table_binlog_row_based_flag();
}
}
/**
- Auxiliary function to close all tables in the open_tables list.
-
- @param thd Thread context.
-
- @remark It should not ordinarily be called directly.
-*/
-
-static void close_open_tables(THD *thd)
-{
- DBUG_PRINT("info", ("thd->open_tables: 0x%lx", (long) thd->open_tables));
-
- while (thd->open_tables)
- (void) close_thread_table(thd, &thd->open_tables);
-}
-
-
-/**
Close all open instances of the table but keep the MDL lock.
Works both under LOCK TABLES and in the normal mode.
@@ -846,6 +648,8 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
ha_extra_function extra,
TABLE *skip_table)
{
+ DBUG_ASSERT(!share->tmp_table);
+
char key[MAX_DBKEY_LENGTH];
uint key_length= share->table_cache_key.length;
const char *db= key;
@@ -923,8 +727,8 @@ void close_thread_tables(THD *thd)
#ifdef EXTRA_DEBUG
DBUG_PRINT("tcache", ("open tables:"));
for (table= thd->open_tables; table; table= table->next)
- DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str,
- table->s->table_name.str, (long) table));
+ DBUG_PRINT("tcache", ("table: '%s'.'%s' %p", table->s->db.str,
+ table->s->table_name.str, table));
#endif
#if defined(ENABLED_DEBUG_SYNC)
@@ -976,10 +780,27 @@ void close_thread_tables(THD *thd)
thd->derived_tables= 0;
}
+ if (thd->rec_tables)
+ {
+ TABLE *next;
+ /*
+ Close all temporary tables created for recursive table references.
+ This action was postponed because the table could be used in the
+ statements like ANALYZE WITH r AS (...) SELECT * from r
+ where r is defined through recursion.
+ */
+ for (table= thd->rec_tables ; table ; table= next)
+ {
+ next= table->next;
+ free_tmp_table(thd, table);
+ }
+ thd->rec_tables= 0;
+ }
+
/*
Mark all temporary tables used by this statement as free for reuse.
*/
- mark_temp_tables_as_free_for_reuse(thd);
+ thd->mark_tmp_tables_as_free_for_reuse();
if (thd->locked_tables_mode)
{
@@ -1034,8 +855,8 @@ void close_thread_tables(THD *thd)
Closing a MERGE child before the parent would be fatal if the
other thread tries to abort the MERGE lock in between.
*/
- if (thd->open_tables)
- close_open_tables(thd);
+ while (thd->open_tables)
+ (void) close_thread_table(thd, &thd->open_tables);
DBUG_VOID_RETURN;
}
@@ -1047,9 +868,9 @@ void close_thread_table(THD *thd, TABLE **table_ptr)
{
TABLE *table= *table_ptr;
DBUG_ENTER("close_thread_table");
- DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str,
- table->s->table_name.str, (long) table));
- DBUG_ASSERT(table->key_read == 0);
+ DBUG_PRINT("tcache", ("table: '%s'.'%s' %p", table->s->db.str,
+ table->s->table_name.str, table));
+ DBUG_ASSERT(!table->file->keyread_enabled());
DBUG_ASSERT(!table->file || table->file->inited == handler::NONE);
/*
@@ -1085,210 +906,13 @@ void close_thread_table(THD *thd, TABLE **table_ptr)
Do this *before* entering the TABLE_SHARE::tdc.LOCK_table_share
critical section.
*/
- if (table->file != NULL)
- MYSQL_UNBIND_TABLE(table->file);
+ MYSQL_UNBIND_TABLE(table->file);
tc_release_table(table);
DBUG_VOID_RETURN;
}
-/* close_temporary_tables' internal, 4 is due to uint4korr definition */
-static inline uint tmpkeyval(THD *thd, TABLE *table)
-{
- return uint4korr(table->s->table_cache_key.str + table->s->table_cache_key.length - 4);
-}
-
-
-/*
- Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
- creates one DROP TEMPORARY TABLE binlog event for each pseudo-thread
-
- Temporary tables created in a sql slave is closed by
- Relay_log_info::close_temporary_tables()
-
-*/
-
-bool close_temporary_tables(THD *thd)
-{
- DBUG_ENTER("close_temporary_tables");
- TABLE *table;
- TABLE *next= NULL;
- TABLE *prev_table;
- /* Assume thd->variables.option_bits has OPTION_QUOTE_SHOW_CREATE */
- bool was_quote_show= TRUE;
- bool error= 0;
-
- if (!thd->temporary_tables)
- DBUG_RETURN(FALSE);
- DBUG_ASSERT(!thd->rgi_slave);
-
- /*
- Ensure we don't have open HANDLERs for tables we are about to close.
- This is necessary when close_temporary_tables() is called as part
- of execution of BINLOG statement (e.g. for format description event).
- */
- mysql_ha_rm_temporary_tables(thd);
- if (!mysql_bin_log.is_open())
- {
- TABLE *tmp_next;
- for (TABLE *t= thd->temporary_tables; t; t= tmp_next)
- {
- tmp_next= t->next;
- mysql_lock_remove(thd, thd->lock, t);
- close_temporary(t, 1, 1);
- }
- thd->temporary_tables= 0;
- DBUG_RETURN(FALSE);
- }
-
- /* Better add "if exists", in case a RESET MASTER has been done */
- const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ";
- char buf[FN_REFLEN];
- String s_query(buf, sizeof(buf), system_charset_info);
- bool found_user_tables= FALSE;
-
- s_query.copy(stub, sizeof(stub)-1, system_charset_info);
-
- /*
- Insertion sort of temp tables by pseudo_thread_id to build ordered list
- of sublists of equal pseudo_thread_id
- */
-
- for (prev_table= thd->temporary_tables, table= prev_table->next;
- table;
- prev_table= table, table= table->next)
- {
- TABLE *prev_sorted /* same as for prev_table */, *sorted;
- if (is_user_table(table))
- {
- if (!found_user_tables)
- found_user_tables= true;
- for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table;
- prev_sorted= sorted, sorted= sorted->next)
- {
- if (!is_user_table(sorted) ||
- tmpkeyval(thd, sorted) > tmpkeyval(thd, table))
- {
- /* move into the sorted part of the list from the unsorted */
- prev_table->next= table->next;
- table->next= sorted;
- if (prev_sorted)
- {
- prev_sorted->next= table;
- }
- else
- {
- thd->temporary_tables= table;
- }
- table= prev_table;
- break;
- }
- }
- }
- }
-
- /* We always quote db,table names though it is slight overkill */
- if (found_user_tables &&
- !(was_quote_show= MY_TEST(thd->variables.option_bits &
- OPTION_QUOTE_SHOW_CREATE)))
- {
- thd->variables.option_bits |= OPTION_QUOTE_SHOW_CREATE;
- }
-
- /* scan sorted tmps to generate sequence of DROP */
- for (table= thd->temporary_tables; table; table= next)
- {
- if (is_user_table(table))
- {
- bool save_thread_specific_used= thd->thread_specific_used;
- my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id;
- char db_buf[FN_REFLEN];
- String db(db_buf, sizeof(db_buf), system_charset_info);
- bool at_least_one_create_logged;
- /* Set pseudo_thread_id to be that of the processed table */
- thd->variables.pseudo_thread_id= tmpkeyval(thd, table);
-
- db.copy(table->s->db.str, table->s->db.length, system_charset_info);
- /* Reset s_query() if changed by previous loop */
- s_query.length(sizeof(stub)-1);
-
- /* Loop forward through all tables that belong to a common database
- within the sublist of common pseudo_thread_id to create single
- DROP query
- */
- for (at_least_one_create_logged= false;
- table && is_user_table(table) &&
- tmpkeyval(thd, table) == thd->variables.pseudo_thread_id &&
- table->s->db.length == db.length() &&
- memcmp(table->s->db.str, db.ptr(), db.length()) == 0;
- table= next)
- {
- if (table->s->table_creation_was_logged)
- {
- at_least_one_create_logged= true;
- /*
- We are going to add ` around the table names and possible more
- due to special characters
- */
- append_identifier(thd, &s_query, table->s->table_name.str,
- strlen(table->s->table_name.str));
- s_query.append(',');
- }
- next= table->next;
- mysql_lock_remove(thd, thd->lock, table);
- close_temporary(table, 1, 1);
- }
- if (at_least_one_create_logged)
- {
- thd->clear_error();
- CHARSET_INFO *cs_save= thd->variables.character_set_client;
- thd->variables.character_set_client= system_charset_info;
- thd->thread_specific_used= TRUE;
- Query_log_event qinfo(thd, s_query.ptr(),
- s_query.length() - 1 /* to remove trailing ',' */,
- FALSE, TRUE, FALSE, 0);
- qinfo.db= db.ptr();
- qinfo.db_len= db.length();
- thd->variables.character_set_client= cs_save;
-
- thd->get_stmt_da()->set_overwrite_status(true);
- thd->transaction.stmt.mark_dropped_temp_table();
- if ((error= (mysql_bin_log.write(&qinfo) || error)))
- {
- /*
- If we're here following THD::cleanup, thence the connection
- has been closed already. So lets print a message to the
- error log instead of pushing yet another error into the
- stmt_da.
-
- Also, we keep the error flag so that we propagate the error
- up in the stack. This way, if we're the SQL thread we notice
- that close_temporary_tables failed. (Actually, the SQL
- thread only calls close_temporary_tables while applying old
- Start_log_event_v3 events.)
- */
- sql_print_error("Failed to write the DROP statement for "
- "temporary tables to binary log");
- }
- thd->get_stmt_da()->set_overwrite_status(false);
- }
- thd->variables.pseudo_thread_id= save_pseudo_thread_id;
- thd->thread_specific_used= save_thread_specific_used;
- }
- else
- {
- next= table->next;
- close_temporary(table, 1, 1);
- }
- }
- if (!was_quote_show)
- thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */
- thd->temporary_tables=0;
-
- DBUG_RETURN(error);
-}
-
/*
Find table in list.
@@ -1315,8 +939,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
{
for (; table; table= table->*link )
{
- if ((table->table == 0 || table->table->s->tmp_table == NO_TMP_TABLE) &&
- strcmp(table->db, db_name) == 0 &&
+ if (strcmp(table->db, db_name) == 0 &&
strcmp(table->table_name, table_name) == 0)
break;
}
@@ -1382,9 +1005,6 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
/* All MyISAMMRG children are plain MyISAM tables. */
DBUG_ASSERT(table->table->file->ht->db_type != DB_TYPE_MRG_MYISAM);
- /* temporary table is always unique */
- if (table->table && table->table->s->tmp_table != NO_TMP_TABLE)
- DBUG_RETURN(0);
table= table->find_underlying_table(table->table);
/*
as far as we have table->table we have to find real TABLE_LIST of
@@ -1421,6 +1041,12 @@ retry:
if (res->table && (res->table == table->table))
continue;
+ /* Skip if table is tmp table */
+ if (check_flag & CHECK_DUP_SKIP_TEMP_TABLE &&
+ res->table && res->table->s->tmp_table != NO_TMP_TABLE)
+ {
+ continue;
+ }
if (check_flag & CHECK_DUP_FOR_CREATE)
DBUG_RETURN(res);
@@ -1461,7 +1087,7 @@ retry:
Try to fix by materializing the derived table
*/
TABLE_LIST *derived= res->belong_to_derived;
- if (derived->is_merged_derived())
+ if (derived->is_merged_derived() && !derived->derived->is_excluded())
{
DBUG_PRINT("info",
("convert merged to materialization to resolve the conflict"));
@@ -1571,292 +1197,6 @@ 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)
-{
- char key[MAX_DBKEY_LENGTH];
- uint key_length= create_tmp_table_def_key(thd, key, db, table_name);
- return find_temporary_table(thd, key, key_length);
-}
-
-
-/**
- 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)
-{
- const char *tmp_key;
- char key[MAX_DBKEY_LENGTH];
- uint key_length;
-
- key_length= get_table_def_key(tl, &tmp_key);
- memcpy(key, tmp_key, key_length);
- int4store(key + key_length, thd->variables.server_id);
- int4store(key + key_length + 4, thd->variables.pseudo_thread_id);
-
- return find_temporary_table(thd, key, key_length + TMP_TABLE_KEY_EXTRA);
-}
-
-
-static bool
-use_temporary_table(THD *thd, TABLE *table, TABLE **out_table)
-{
- *out_table= table;
- if (!table)
- return false;
- /*
- Temporary tables are not safe for parallel replication. They were
- designed to be visible to one thread only, so have no table locking.
- Thus there is no protection against two conflicting transactions
- committing in parallel and things like that.
-
- So for now, anything that uses temporary tables will be serialised
- with anything before it, when using parallel replication.
-
- ToDo: We might be able to introduce a reference count or something
- on temp tables, and have slave worker threads wait for it to reach
- zero before being allowed to use the temp table. Might not be worth
- it though, as statement-based replication using temporary tables is
- in any case rather fragile.
- */
- if (thd->rgi_slave && thd->rgi_slave->is_parallel_exec &&
- thd->wait_for_prior_commit())
- return true;
- /*
- We need to set the THD as it may be different in case of
- parallel replication
- */
- if (table->in_use != thd)
- {
- table->in_use= thd;
-#ifdef REMOVE_AFTER_MERGE_WITH_10
- if (thd->rgi_slave)
- {
- /*
- We may be stealing an opened temporary tables from one slave
- thread to another, we need to let the performance schema know that,
- for aggregates per thread to work properly.
- */
- MYSQL_UNBIND_TABLE(table->file);
- MYSQL_REBIND_TABLE(table->file);
- }
-#endif
- }
- return false;
-}
-
-bool
-find_and_use_temporary_table(THD *thd, const char *db, const char *table_name,
- TABLE **out_table)
-{
- return use_temporary_table(thd, find_temporary_table(thd, db, table_name),
- out_table);
-}
-
-
-bool
-find_and_use_temporary_table(THD *thd, const TABLE_LIST *tl, TABLE **out_table)
-{
- return use_temporary_table(thd, find_temporary_table(thd, tl), out_table);
-}
-
-
-/**
- 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)
-{
- TABLE *result= 0;
- if (!thd->have_temporary_tables())
- return NULL;
-
- thd->lock_temporary_tables();
- for (TABLE *table= thd->temporary_tables; table; table= table->next)
- {
- if (table->s->table_cache_key.length == table_key_length &&
- !memcmp(table->s->table_cache_key.str, table_key, table_key_length))
- {
- result= table;
- break;
- }
- }
- thd->unlock_temporary_tables(0);
- return result;
-}
-
-
-/**
- Drop a temporary table.
-
- Try to locate the table in the list of thd->temporary_tables.
- If the table is found:
- - if the table is being used by some outer statement, fail.
- - if the table is locked with LOCK TABLES or by prelocking,
- unlock it and remove it from the list of locked tables
- (THD::lock). Currently only transactional temporary tables
- are locked.
- - Close the temporary table, remove its .FRM
- - remove the table from the list of temporary tables
-
- This function is used to drop user temporary tables, as well as
- internal tables created in CREATE TEMPORARY TABLE ... SELECT
- or ALTER TABLE. Even though part of the work done by this function
- is redundant when the table is internal, as long as we
- link both internal and user temporary tables into the same
- thd->temporary_tables list, it's impossible to tell here whether
- we're dealing with an internal or a user temporary table.
-
- @param thd Thread handler
- @param table Temporary table to be deleted
- @param is_trans Is set to the type of the table:
- transactional (e.g. innodb) as TRUE or non-transactional
- (e.g. myisam) as FALSE.
-
- @retval 0 the table was found and dropped successfully.
- @retval -1 the table is in use by a outer query
-*/
-
-int drop_temporary_table(THD *thd, TABLE *table, bool *is_trans)
-{
- DBUG_ENTER("drop_temporary_table");
- DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
- table->s->db.str, table->s->table_name.str));
-
- /* Table might be in use by some outer statement. */
- if (table->query_id && table->query_id != thd->query_id)
- {
- DBUG_PRINT("info", ("table->query_id: %lu thd->query_id: %lu",
- (ulong) table->query_id, (ulong) thd->query_id));
-
- my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias.c_ptr());
- DBUG_RETURN(-1);
- }
-
- *is_trans= table->file->has_transactions();
-
- /*
- If LOCK TABLES list is not empty and contains this table,
- unlock the table and remove the table from this list.
- */
- mysql_lock_remove(thd, thd->lock, table);
- close_temporary_table(thd, table, 1, 1);
- DBUG_RETURN(0);
-}
-
-
-/*
- unlink from thd->temporary tables and close temporary table
-*/
-
-void close_temporary_table(THD *thd, TABLE *table,
- bool free_share, bool delete_table)
-{
- DBUG_ENTER("close_temporary_table");
- DBUG_PRINT("tmptable", ("closing table: '%s'.'%s' 0x%lx alias: '%s'",
- table->s->db.str, table->s->table_name.str,
- (long) table, table->alias.c_ptr()));
-
- thd->lock_temporary_tables();
- if (table->prev)
- {
- table->prev->next= table->next;
- if (table->prev->next)
- table->next->prev= table->prev;
- }
- else
- {
- /* removing the item from the list */
- DBUG_ASSERT(table == thd->temporary_tables);
- /*
- slave must reset its temporary list pointer to zero to exclude
- passing non-zero value to end_slave via rli->save_temporary_tables
- when no temp tables opened, see an invariant below.
- */
- thd->temporary_tables= table->next;
- if (thd->temporary_tables)
- table->next->prev= 0;
- }
- if (thd->rgi_slave)
- {
- /* natural invariant of temporary_tables */
- DBUG_ASSERT(slave_open_temp_tables || !thd->temporary_tables);
- thread_safe_decrement32(&slave_open_temp_tables);
- table->in_use= 0; // No statistics
- }
- thd->unlock_temporary_tables(0);
- close_temporary(table, free_share, delete_table);
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Close and delete a temporary table
-
- NOTE
- This dosn't unlink table from thd->temporary
- If this is needed, use close_temporary_table()
-*/
-
-void close_temporary(TABLE *table, bool free_share, bool delete_table)
-{
- handlerton *table_type= table->s->db_type();
- DBUG_ENTER("close_temporary");
- DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
- table->s->db.str, table->s->table_name.str));
-
- free_io_cache(table);
- closefrm(table, 0);
- if (delete_table)
- rm_temporary_table(table_type, table->s->path.str);
- if (free_share)
- {
- free_table_share(table->s);
- my_free(table);
- }
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Used by ALTER TABLE when the table is a temporary one. It changes something
- only if the ALTER contained a RENAME clause (otherwise, table_name is the old
- name).
- Prepares a table cache key, which is the concatenation of db, table_name and
- thd->slave_proxy_id, separated by '\0'.
-*/
-
-bool rename_temporary_table(THD* thd, TABLE *table, const char *db,
- const char *table_name)
-{
- char *key;
- uint key_length;
- TABLE_SHARE *share= table->s;
- DBUG_ENTER("rename_temporary_table");
-
- if (!(key=(char*) alloc_root(&share->mem_root, MAX_DBKEY_LENGTH)))
- DBUG_RETURN(1); /* purecov: inspected */
-
- key_length= create_tmp_table_def_key(thd, key, db, table_name);
- share->set_table_cache_key(key, key_length);
- DBUG_RETURN(0);
-}
-
-
-/**
Force all other threads to stop using the table by upgrading
metadata lock on it and remove unused TABLE instances from cache.
@@ -1878,8 +1218,9 @@ bool wait_while_table_is_used(THD *thd, TABLE *table,
enum ha_extra_function function)
{
DBUG_ENTER("wait_while_table_is_used");
- DBUG_PRINT("enter", ("table: '%s' share: 0x%lx db_stat: %u version: %lu",
- table->s->table_name.str, (ulong) table->s,
+ DBUG_ASSERT(!table->s->tmp_table);
+ DBUG_PRINT("enter", ("table: '%s' share: %p db_stat: %u version: %lld",
+ table->s->table_name.str, table->s,
table->db_stat, table->s->tdc->version));
if (thd->mdl_context.upgrade_shared_lock(
@@ -1921,7 +1262,7 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name,
{
DBUG_ENTER("drop_open_table");
if (table->s->tmp_table)
- close_temporary_table(thd, table, 1, 1);
+ thd->drop_temporary_table(table, NULL, true);
else
{
DBUG_ASSERT(table == thd->open_tables);
@@ -1957,7 +1298,7 @@ public:
virtual bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
- Sql_condition::enum_warning_level level,
+ Sql_condition::enum_warning_level *level,
const char* msg,
Sql_condition ** cond_hdl);
@@ -1976,7 +1317,7 @@ private:
bool MDL_deadlock_handler::handle_condition(THD *,
uint sql_errno,
const char*,
- Sql_condition::enum_warning_level,
+ Sql_condition::enum_warning_level*,
const char*,
Sql_condition ** cond_hdl)
{
@@ -2177,7 +1518,7 @@ bool is_locked_view(THD *thd, TABLE_LIST *t)
DBUG_RETURN(FALSE);
}
- if (!tdc_open_view(thd, t, t->alias, CHECK_METADATA_VERSION))
+ if (!tdc_open_view(thd, t, CHECK_METADATA_VERSION))
{
DBUG_ASSERT(t->view != 0);
DBUG_RETURN(TRUE); // VIEW
@@ -2258,7 +1599,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
Note that we allow write locks on log tables as otherwise logging
to general/slow log would be disabled in read only transactions.
*/
- if (table_list->mdl_request.type >= MDL_SHARED_WRITE &&
+ if (table_list->mdl_request.is_write_lock_request() &&
thd->tx_read_only &&
!(flags & (MYSQL_LOCK_LOG_TABLE | MYSQL_OPEN_HAS_MDL_LOCK)))
{
@@ -2266,6 +1607,12 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
DBUG_RETURN(true);
}
+ if (!table_list->db)
+ {
+ my_error(ER_NO_DB_ERROR, MYF(0));
+ DBUG_RETURN(true);
+ }
+
key_length= get_table_def_key(table_list, &key);
/*
@@ -2378,7 +1725,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
pre-acquiring metadata locks at the beggining of
open_tables() call.
*/
- if (table_list->mdl_request.type >= MDL_SHARED_WRITE &&
+ if (table_list->mdl_request.is_write_lock_request() &&
! (flags & (MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
MYSQL_OPEN_FORCE_SHARED_MDL |
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
@@ -2446,10 +1793,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
retry_share:
- share= tdc_acquire_share(thd, table_list->db, table_list->table_name,
- key, key_length,
- table_list->mdl_request.key.tc_hash_value(),
- gts_flags, &table);
+ share= tdc_acquire_share(thd, table_list, gts_flags, &table);
if (!share)
{
@@ -2518,7 +1862,7 @@ retry_share:
{
if (share->tdc->flushed)
{
- DBUG_PRINT("info", ("Found old share version: %lu current: %lu",
+ 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
@@ -2582,12 +1926,8 @@ retry_share:
goto err_lock;
error= open_table_from_share(thd, share, alias,
- (uint) (HA_OPEN_KEYFILE |
- HA_OPEN_RNDFILE |
- HA_GET_INDEX |
- HA_TRY_READ_ONLY),
- (READ_KEYINFO | COMPUTE_TYPES |
- EXTRA_RECORD),
+ HA_OPEN_KEYFILE | HA_TRY_READ_ONLY,
+ EXTRA_RECORD,
thd->open_options, table, FALSE);
if (error)
@@ -2609,7 +1949,7 @@ retry_share:
}
if (open_table_entry_fini(thd, share, table))
{
- closefrm(table, 0);
+ closefrm(table);
my_free(table);
goto err_lock;
}
@@ -2830,6 +2170,9 @@ Locked_tables_list::init_locked_tables(THD *thd)
return TRUE;
}
}
+
+ TRANSACT_TRACKER(add_trx_state(thd, TX_LOCKED_TABLES));
+
thd->enter_locked_tables_mode(LTM_LOCK_TABLES);
return FALSE;
@@ -2870,6 +2213,8 @@ Locked_tables_list::unlock_locked_tables(THD *thd)
}
thd->leave_locked_tables_mode();
+ TRANSACT_TRACKER(clear_trx_state(thd, TX_LOCKED_TABLES));
+
DBUG_ASSERT(thd->transaction.stmt.is_empty());
close_thread_tables(thd);
@@ -3026,6 +2371,7 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count)
DBUG_ASSERT(thd->open_tables == m_reopen_array[reopen_count]);
thd->open_tables->pos_in_locked_tables->table= NULL;
+ thd->open_tables->pos_in_locked_tables= 0;
close_thread_table(thd, &thd->open_tables);
}
@@ -3080,9 +2426,17 @@ Locked_tables_list::reopen_tables(THD *thd, bool need_reopen)
{
if (!table_list->table || !table_list->table->needs_reopen())
continue;
- /* no need to remove the table from the TDC here, thus (TABLE*)1 */
- close_all_tables_for_name(thd, table_list->table->s,
- HA_EXTRA_NOT_USED, (TABLE*)1);
+ for (TABLE **prev= &thd->open_tables; *prev; prev= &(*prev)->next)
+ {
+ if (*prev == table_list->table)
+ {
+ thd->locked_tables_list.unlink_from_list(thd, table_list, false);
+ mysql_lock_remove(thd, thd->lock, *prev);
+ (*prev)->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE);
+ close_thread_table(thd, prev);
+ break;
+ }
+ }
DBUG_ASSERT(table_list->table == NULL);
}
else
@@ -3328,9 +2682,6 @@ check_and_update_routine_version(THD *thd, Sroutine_hash_entry *rt,
@param thd Thread handle
@param table_list TABLE_LIST with db, table_name & belong_to_view
- @param alias Alias name
- @param cache_key Key for table definition cache
- @param cache_key_length Length of cache_key
@param flags Flags which modify how we open the view
@todo This function is needed for special handling of views under
@@ -3339,16 +2690,13 @@ check_and_update_routine_version(THD *thd, Sroutine_hash_entry *rt,
@return FALSE if success, TRUE - otherwise.
*/
-bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
- const char *cache_key, uint cache_key_length,
- uint flags)
+bool tdc_open_view(THD *thd, TABLE_LIST *table_list, uint flags)
{
TABLE not_used;
TABLE_SHARE *share;
bool err= TRUE;
- if (!(share= tdc_acquire_share(thd, table_list->db, table_list->table_name,
- cache_key, cache_key_length, GTS_VIEW)))
+ if (!(share= tdc_acquire_share(thd, table_list, GTS_VIEW)))
return TRUE;
DBUG_ASSERT(share->is_view);
@@ -3435,16 +2783,14 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list)
if (!(entry= (TABLE*)my_malloc(sizeof(TABLE), MYF(MY_WME))))
return result;
- if (!(share= tdc_acquire_share_shortlived(thd, table_list, GTS_TABLE)))
+ if (!(share= tdc_acquire_share(thd, table_list, GTS_TABLE)))
goto end_free;
DBUG_ASSERT(! share->is_view);
if (open_table_from_share(thd, share, table_list->alias,
- (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
- HA_GET_INDEX |
- HA_TRY_READ_ONLY),
- READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
+ 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)))
@@ -3455,12 +2801,12 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list)
sql_print_error("Couldn't repair table: %s.%s", share->db.str,
share->table_name.str);
if (entry->file)
- closefrm(entry, 0);
+ closefrm(entry);
}
else
{
thd->clear_error(); // Clear error message
- closefrm(entry, 0);
+ closefrm(entry);
result= FALSE;
}
@@ -3592,7 +2938,7 @@ public:
virtual bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
- Sql_condition::enum_warning_level level,
+ Sql_condition::enum_warning_level *level,
const char* msg,
Sql_condition ** cond_hdl)
{
@@ -3654,8 +3000,7 @@ Open_table_context::recover_from_failed_open()
if (open_if_exists)
m_thd->push_internal_handler(&no_such_table_handler);
- result= !tdc_acquire_share(m_thd, m_failed_table->db,
- m_failed_table->table_name,
+ result= !tdc_acquire_share(m_thd, m_failed_table,
GTS_TABLE | GTS_FORCE_DISCOVERY | GTS_NOLOCK);
if (open_if_exists)
{
@@ -4025,6 +3370,58 @@ open_and_process_table(THD *thd, TABLE_LIST *tables, uint *counter, uint flags,
tables->table_name= tables->view_name.str;
tables->table_name_length= tables->view_name.length;
}
+ else if (tables->select_lex)
+ {
+ /*
+ Check whether 'tables' refers to a table defined in a with clause.
+ If so set the reference to the definition in tables->with.
+ */
+ if (!tables->with)
+ tables->with= tables->select_lex->find_table_def_in_with_clauses(tables);
+ /*
+ If 'tables' is defined in a with clause set the pointer to the
+ specification from its definition in tables->derived.
+ */
+ if (tables->with)
+ {
+ if (tables->is_recursive_with_table() &&
+ !tables->is_with_table_recursive_reference())
+ {
+ tables->with->rec_outer_references++;
+ With_element *with_elem= tables->with;
+ while ((with_elem= with_elem->get_next_mutually_recursive()) !=
+ tables->with)
+ with_elem->rec_outer_references++;
+ }
+ if (tables->set_as_with_table(thd, tables->with))
+ DBUG_RETURN(1);
+ else
+ goto end;
+ }
+ }
+
+ if (!tables->derived &&
+ is_infoschema_db(tables->db, tables->db_length))
+ {
+ /*
+ Check whether the information schema contains a table
+ whose name is tables->schema_table_name
+ */
+ ST_SCHEMA_TABLE *schema_table= tables->schema_table;
+ if (!schema_table ||
+ (schema_table->hidden &&
+ ((sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0 ||
+ /*
+ this check is used for show columns|keys from I_S hidden table
+ */
+ lex->sql_command == SQLCOM_SHOW_FIELDS ||
+ lex->sql_command == SQLCOM_SHOW_KEYS)))
+ {
+ my_error(ER_UNKNOWN_TABLE, MYF(0),
+ tables->table_name, INFORMATION_SCHEMA_NAME.str);
+ DBUG_RETURN(1);
+ }
+ }
/*
If this TABLE_LIST object is a placeholder for an information_schema
table, create a temporary table to represent the information_schema
@@ -4110,7 +3507,7 @@ open_and_process_table(THD *thd, TABLE_LIST *tables, uint *counter, uint flags,
of temporary tables we have to try to open temporary table for it.
We can't simply skip this table list element and postpone opening of
- temporary tabletill the execution of substatement for several reasons:
+ temporary table till the execution of substatement for several reasons:
- Temporary table can be a MERGE table with base underlying tables,
so its underlying tables has to be properly open and locked at
prelocking stage.
@@ -4126,7 +3523,7 @@ 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= open_temporary_table(thd, tables);
+ error= thd->open_temporary_table(tables);
if (!error && !tables->table)
error= open_table(thd, tables, ot_ctx);
@@ -4145,7 +3542,8 @@ 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= open_temporary_table(thd, tables);
+ error= thd->open_temporary_table(tables);
+
if (!error && !tables->table)
error= open_table(thd, tables, ot_ctx);
@@ -4161,7 +3559,7 @@ 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= open_temporary_table(thd, tables);
+ error= thd->open_temporary_table(tables);
}
if (!error && !tables->table)
@@ -4278,6 +3676,7 @@ end:
new locks, so use open_tables_check_upgradable_mdl() instead.
@param thd Thread context.
+ @param options DDL options.
@param tables_start Start of list of tables on which upgradable locks
should be acquired.
@param tables_end End of list of tables.
@@ -4320,6 +3719,7 @@ lock_table_names(THD *thd, const DDL_options_st &options,
table= table->next_global)
{
if (table->mdl_request.type < MDL_SHARED_UPGRADABLE ||
+ table->mdl_request.type == MDL_SHARED_READ_ONLY ||
table->open_type == OT_TEMPORARY_ONLY ||
(table->open_type == OT_TEMPORARY_OR_BASE && is_temporary_table(table)))
{
@@ -4448,6 +3848,11 @@ open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
for (table= tables_start; table && table != tables_end;
table= table->next_global)
{
+ /*
+ Check below needs to be updated if this function starts
+ called for SRO locks.
+ */
+ DBUG_ASSERT(table->mdl_request.type != MDL_SHARED_READ_ONLY);
if (table->mdl_request.type < MDL_SHARED_UPGRADABLE ||
table->open_type == OT_TEMPORARY_ONLY ||
(table->open_type == OT_TEMPORARY_OR_BASE && is_temporary_table(table)))
@@ -4485,6 +3890,7 @@ open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
Open all tables in list
@param[in] thd Thread context.
+ @param[in] options DDL options.
@param[in,out] start List of tables to be open (it can be adjusted for
statement that uses tables only implicitly, e.g.
for "SELECT f1()").
@@ -4658,7 +4064,7 @@ restart:
goto error;
/* Re-open temporary tables after close_tables_for_reopen(). */
- if (open_temporary_tables(thd, *start))
+ if (thd->open_temporary_tables(*start))
goto error;
error= FALSE;
@@ -4720,7 +4126,7 @@ restart:
goto error;
/* Re-open temporary tables after close_tables_for_reopen(). */
- if (open_temporary_tables(thd, *start))
+ if (thd->open_temporary_tables(*start))
goto error;
error= FALSE;
@@ -4872,6 +4278,7 @@ handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
@note this can be changed to use a hash, instead of scanning the linked
list, if the performance of this function will ever become an issue
*/
+
bool table_already_fk_prelocked(TABLE_LIST *tl, LEX_STRING *db,
LEX_STRING *table, thr_lock_type lock_type)
{
@@ -4949,11 +4356,12 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
while ((fk= fk_list_it++))
{
// FK_OPTION_RESTRICT and FK_OPTION_NO_ACTION only need read access
+ static bool can_write[]= { true, false, true, true, false, true };
uint8 op= table_list->trg_event_map;
thr_lock_type lock_type;
- if ((op & (1 << TRG_EVENT_DELETE) && fk_modifies_child(fk->delete_method))
- || (op & (1 << TRG_EVENT_UPDATE) && fk_modifies_child(fk->update_method)))
+ if ((op & (1 << TRG_EVENT_DELETE) && can_write[fk->delete_method])
+ || (op & (1 << TRG_EVENT_UPDATE) && can_write[fk->update_method]))
lock_type= TL_WRITE_ALLOW_WRITE;
else
lock_type= TL_READ;
@@ -5162,6 +4570,13 @@ static bool check_lock_and_start_stmt(THD *thd,
table_list->table->file->print_error(error, MYF(0));
DBUG_RETURN(1);
}
+
+ /*
+ Record in transaction state tracking
+ */
+ TRANSACT_TRACKER(add_trx_state(thd, lock_type,
+ table_list->table->file->has_transactions()));
+
DBUG_RETURN(0);
}
@@ -5261,7 +4676,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
bool error;
DBUG_ENTER("open_ltable");
- /* Ignore temporary tables as they have already ben opened*/
+ /* Ignore temporary tables as they have already been opened. */
if (table_list->table)
DBUG_RETURN(table_list->table);
@@ -5348,8 +4763,9 @@ end:
Open all tables in list, locks them and optionally process derived tables.
@param thd Thread context.
+ @param options DDL options.
@param tables List of tables for open and locking.
- @param derived If to handle derived tables.
+ @param derived Whether to handle derived tables.
@param flags Bitmap of options to be used to open and lock
tables (see open_tables() and mysql_lock_tables()
for details).
@@ -5494,6 +4910,45 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table_list)
}
+static bool fix_all_session_vcol_exprs(THD *thd, TABLE_LIST *tables)
+{
+ Security_context *save_security_ctx= thd->security_ctx;
+ TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
+ DBUG_ENTER("fix_session_vcol_expr");
+
+ for (TABLE_LIST *table= tables; table && table != first_not_own;
+ table= table->next_global)
+ {
+ TABLE *t= table->table;
+ if (!table->placeholder() && t->s->vcols_need_refixing &&
+ table->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ if (table->security_ctx)
+ thd->security_ctx= table->security_ctx;
+
+ for (Field **vf= t->vfield; vf && *vf; vf++)
+ if (fix_session_vcol_expr(thd, (*vf)->vcol_info))
+ goto err;
+
+ for (Field **df= t->default_field; df && *df; df++)
+ if ((*df)->default_value &&
+ fix_session_vcol_expr(thd, (*df)->default_value))
+ goto err;
+
+ for (Virtual_column_info **cc= t->check_constraints; cc && *cc; cc++)
+ if (fix_session_vcol_expr(thd, (*cc)))
+ goto err;
+
+ thd->security_ctx= save_security_ctx;
+ }
+ }
+ DBUG_RETURN(0);
+err:
+ thd->security_ctx= save_security_ctx;
+ DBUG_RETURN(1);
+}
+
+
/**
Lock all tables in a list.
@@ -5655,7 +5110,11 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
}
}
- DBUG_RETURN(thd->decide_logging_format(tables));
+ bool res= fix_all_session_vcol_exprs(thd, tables);
+ if (!res)
+ res= thd->decide_logging_format(tables);
+
+ DBUG_RETURN(res);
}
@@ -5744,176 +5203,6 @@ void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
}
-/**
- 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 hton Storage engine of the table, if known,
- or NULL otherwise.
- @param frm frm image
- @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.
- @param open_in_engine Indicates that we need to open table
- in storage engine in addition to
- constructing TABLE object for it.
-
- @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_table_uncached(THD *thd, handlerton *hton,
- LEX_CUSTRING *frm,
- const char *path, const char *db,
- const char *table_name,
- bool add_to_temporary_tables_list,
- bool open_in_engine)
-{
- TABLE *tmp_table;
- TABLE_SHARE *share;
- char cache_key[MAX_DBKEY_LENGTH], *saved_cache_key, *tmp_path;
- uint key_length;
- DBUG_ENTER("open_table_uncached");
- DBUG_PRINT("enter",
- ("table: '%s'.'%s' path: '%s' server_id: %u "
- "pseudo_thread_id: %lu",
- db, table_name, path,
- (uint) thd->variables.server_id,
- (ulong) thd->variables.pseudo_thread_id));
-
- if (add_to_temporary_tables_list)
- {
- /* Temporary tables are not safe for parallel replication. */
- if (thd->rgi_slave && thd->rgi_slave->is_parallel_exec &&
- thd->wait_for_prior_commit())
- DBUG_RETURN(NULL);
- }
-
- /* Create the cache_key for temporary tables */
- key_length= create_tmp_table_def_key(thd, cache_key, db, table_name);
-
- if (!(tmp_table= (TABLE*) my_malloc(sizeof(*tmp_table) + sizeof(*share) +
- strlen(path)+1 + key_length,
- MYF(MY_WME))))
- DBUG_RETURN(0); /* purecov: inspected */
-
- share= (TABLE_SHARE*) (tmp_table+1);
- tmp_path= (char*) (share+1);
- saved_cache_key= strmov(tmp_path, path)+1;
- memcpy(saved_cache_key, cache_key, key_length);
-
- init_tmp_table_share(thd, share, saved_cache_key, key_length,
- strend(saved_cache_key)+1, tmp_path);
- share->db_plugin= ha_lock_engine(thd, hton);
-
- /*
- Use the frm image, if possible, open the file otherwise.
-
- The image might be unavailable in ALTER TABLE, when the discovering
- engine took over the ownership (see TABLE::read_frm_image).
- */
- int res= frm->str
- ? share->init_from_binary_frm_image(thd, false, frm->str, frm->length)
- : open_table_def(thd, share, GTS_TABLE | GTS_USE_DISCOVERY);
-
- if (res)
- {
- /* No need to lock share->mutex as this is not needed for tmp tables */
- free_table_share(share);
- my_free(tmp_table);
- DBUG_RETURN(0);
- }
-
- share->m_psi= PSI_CALL_get_table_share(true, share);
-
- if (open_table_from_share(thd, share, table_name,
- open_in_engine ?
- (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
- HA_GET_INDEX) : 0,
- READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
- ha_open_options,
- tmp_table,
- /*
- Set "is_create_table" if the table does not
- exist in SE
- */
- open_in_engine ? false : true))
- {
- /* No need to lock share->mutex as this is not needed for tmp tables */
- free_table_share(share);
- my_free(tmp_table);
- DBUG_RETURN(0);
- }
-
- tmp_table->reginfo.lock_type= TL_WRITE; // Simulate locked
- tmp_table->grant.privilege= TMP_TABLE_ACLS;
- share->tmp_table= (tmp_table->file->has_transactions() ?
- TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE);
-
- if (add_to_temporary_tables_list)
- {
- thd->lock_temporary_tables();
- /* growing temp list at the head */
- tmp_table->next= thd->temporary_tables;
- if (tmp_table->next)
- tmp_table->next->prev= tmp_table;
- thd->temporary_tables= tmp_table;
- thd->temporary_tables->prev= 0;
- if (thd->rgi_slave)
- {
- thread_safe_increment32(&slave_open_temp_tables);
- }
- thd->unlock_temporary_tables(0);
- }
- tmp_table->pos_in_table_list= 0;
- DBUG_PRINT("tmptable", ("opened table: '%s'.'%s' 0x%lx", tmp_table->s->db.str,
- tmp_table->s->table_name.str, (long) tmp_table));
- DBUG_RETURN(tmp_table);
-}
-
-
-/**
- Delete a temporary table.
-
- @param base Handlerton for table to be deleted.
- @param path Path to the table to be deleted (i.e. path
- to its .frm without an extension).
-
- @retval false - success.
- @retval true - failure.
-*/
-
-bool rm_temporary_table(handlerton *base, const char *path)
-{
- bool error=0;
- handler *file;
- char frm_path[FN_REFLEN + 1];
- DBUG_ENTER("rm_temporary_table");
-
- strxnmov(frm_path, sizeof(frm_path) - 1, path, reg_ext, NullS);
- if (mysql_file_delete(key_file_frm, frm_path, MYF(0)))
- error=1; /* purecov: inspected */
- file= get_new_handler((TABLE_SHARE*) 0, current_thd->mem_root, base);
- if (file && file->ha_delete_table(path))
- {
- error=1;
- sql_print_warning("Could not remove temporary table: '%s', error: %d",
- path, my_errno);
- }
- delete file;
- DBUG_RETURN(error);
-}
-
-
/*****************************************************************************
* The following find_field_in_XXX procedures implement the core of the
* name resolution functionality. The entry point to resolve a column name in a
@@ -5942,7 +5231,6 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
*/
table->covering_keys.intersect(field->part_of_key);
- table->merge_keys.merge(field->part_of_key);
if (field->vcol_info)
table->mark_virtual_col(field);
@@ -5982,164 +5270,6 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
}
-/**
- Find a temporary table specified by TABLE_LIST instance in the cache and
- prepare its TABLE instance for use.
-
- This function tries to resolve this table in the list of temporary tables
- of this thread. Temporary tables are thread-local and "shadow" base
- tables with the same name.
-
- @note In most cases one should use open_temporary_tables() instead
- of this call.
-
- @note One should finalize process of opening temporary table for table
- list element by calling open_and_process_table(). This function
- is responsible for table version checking and handling of merge
- tables.
-
- @note We used to check global_read_lock before opening temporary tables.
- However, that limitation was artificial and is removed now.
-
- @return Error status.
- @retval FALSE On success. If a temporary table exists for the given
- key, tl->table is set.
- @retval TRUE On error. my_error() has been called.
-*/
-
-bool open_temporary_table(THD *thd, TABLE_LIST *tl)
-{
- TABLE *table;
- DBUG_ENTER("open_temporary_table");
- DBUG_PRINT("enter", ("table: '%s'.'%s'", tl->db, tl->table_name));
-
- /*
- Code in open_table() assumes that TABLE_LIST::table can
- be non-zero only for pre-opened temporary tables.
- */
- DBUG_ASSERT(tl->table == NULL);
-
- /*
- This function should not be called for cases when derived or I_S
- tables can be met since table list elements for such tables can
- have invalid db or table name.
- Instead open_temporary_tables() should be used.
- */
- DBUG_ASSERT(!tl->derived && !tl->schema_table);
-
- if (tl->open_type == OT_BASE_ONLY || !thd->have_temporary_tables())
- {
- DBUG_PRINT("info", ("skip_temporary is set or no temporary tables"));
- DBUG_RETURN(FALSE);
- }
-
- if (find_and_use_temporary_table(thd, tl, &table))
- DBUG_RETURN(TRUE);
- if (!table)
- {
- if (tl->open_type == OT_TEMPORARY_ONLY &&
- tl->open_strategy == TABLE_LIST::OPEN_NORMAL)
- {
- my_error(ER_NO_SUCH_TABLE, MYF(0), tl->db, tl->table_name);
- DBUG_RETURN(TRUE);
- }
- DBUG_RETURN(FALSE);
- }
-
- /*
- Temporary tables are not safe for parallel replication. They were
- designed to be visible to one thread only, so have no table locking.
- Thus there is no protection against two conflicting transactions
- committing in parallel and things like that.
-
- So for now, anything that uses temporary tables will be serialised
- with anything before it, when using parallel replication.
-
- ToDo: We might be able to introduce a reference count or something
- on temp tables, and have slave worker threads wait for it to reach
- zero before being allowed to use the temp table. Might not be worth
- it though, as statement-based replication using temporary tables is
- in any case rather fragile.
- */
- if (thd->rgi_slave && thd->rgi_slave->is_parallel_exec &&
- thd->wait_for_prior_commit())
- DBUG_RETURN(true);
-
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- if (tl->partition_names)
- {
- /* Partitioned temporary tables is not supported. */
- DBUG_ASSERT(!table->part_info);
- my_error(ER_PARTITION_CLAUSE_ON_NONPARTITIONED, MYF(0));
- DBUG_RETURN(true);
- }
-#endif
-
- if (table->query_id)
- {
- /*
- We're trying to use the same temporary table twice in a query.
- Right now we don't support this because a temporary table is always
- represented by only one TABLE object in THD, and it can not be
- cloned. Emit an error for an unsupported behaviour.
- */
-
- DBUG_PRINT("error",
- ("query_id: %lu server_id: %u pseudo_thread_id: %lu",
- (ulong) table->query_id, (uint) thd->variables.server_id,
- (ulong) thd->variables.pseudo_thread_id));
- my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias.c_ptr());
- DBUG_RETURN(TRUE);
- }
-
- table->query_id= thd->query_id;
- thd->thread_specific_used= TRUE;
-
- tl->updatable= 1; // It is not derived table nor non-updatable VIEW.
- tl->table= table;
-
- table->init(thd, tl);
-
- DBUG_PRINT("info", ("Using temporary table"));
- DBUG_RETURN(FALSE);
-}
-
-
-/**
- Pre-open temporary tables corresponding to table list elements.
-
- @note One should finalize process of opening temporary tables
- by calling open_tables(). This function is responsible
- for table version checking and handling of merge tables.
-
- @return Error status.
- @retval FALSE On success. If a temporary tables exists for the
- given element, tl->table is set.
- @retval TRUE On error. my_error() has been called.
-*/
-
-bool open_temporary_tables(THD *thd, TABLE_LIST *tl_list)
-{
- TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
- DBUG_ENTER("open_temporary_tables");
-
- for (TABLE_LIST *tl= tl_list; tl && tl != first_not_own; tl= tl->next_global)
- {
- if (tl->derived || tl->schema_table)
- {
- /*
- Derived and I_S tables will be handled by a later call to open_tables().
- */
- continue;
- }
-
- if (open_temporary_table(thd, tl))
- DBUG_RETURN(TRUE);
- }
-
- DBUG_RETURN(FALSE);
-}
-
/*
Find a field by name in a view that uses merge algorithm.
@@ -6169,8 +5299,8 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
{
DBUG_ENTER("find_field_in_view");
DBUG_PRINT("enter",
- ("view: '%s', field name: '%s', item name: '%s', ref 0x%lx",
- table_list->alias, name, item_name, (ulong) ref));
+ ("view: '%s', field name: '%s', item name: '%s', ref %p",
+ table_list->alias, name, item_name, ref));
Field_iterator_view field_it;
field_it.set(table_list);
Query_arena *arena= 0, backup;
@@ -6214,9 +5344,9 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
}
else
{
- item->set_name((*ref)->name, (*ref)->name_length,
+ item->set_name(thd, (*ref)->name, (*ref)->name_length,
system_charset_info);
- item->real_item()->set_name((*ref)->name, (*ref)->name_length,
+ item->real_item()->set_name(thd, (*ref)->name, (*ref)->name_length,
system_charset_info);
}
}
@@ -6271,8 +5401,8 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
Field *UNINIT_VAR(found_field);
Query_arena *UNINIT_VAR(arena), backup;
DBUG_ENTER("find_field_in_natural_join");
- DBUG_PRINT("enter", ("field name: '%s', ref 0x%lx",
- name, (ulong) ref));
+ DBUG_PRINT("enter", ("field name: '%s', ref %p",
+ name, ref));
DBUG_ASSERT(table_ref->is_natural_join && table_ref->join_columns);
DBUG_ASSERT(*actual_table == NULL);
@@ -6313,9 +5443,9 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
*/
if (*ref && !(*ref)->is_autogenerated_name)
{
- item->set_name((*ref)->name, (*ref)->name_length,
+ item->set_name(thd, (*ref)->name, (*ref)->name_length,
system_charset_info);
- item->real_item()->set_name((*ref)->name, (*ref)->name_length,
+ item->real_item()->set_name(thd, (*ref)->name, (*ref)->name_length,
system_charset_info);
}
if (register_tree_change && arena)
@@ -6428,7 +5558,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
if (field_ptr && *field_ptr)
{
- *cached_field_index_ptr= field_ptr - table->field;
+ *cached_field_index_ptr= (uint)(field_ptr - table->field);
field= *field_ptr;
}
else
@@ -6505,8 +5635,8 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
DBUG_ASSERT(name);
DBUG_ASSERT(item_name);
DBUG_PRINT("enter",
- ("table: '%s' field name: '%s' item name: '%s' ref 0x%lx",
- table_list->alias, name, item_name, (ulong) ref));
+ ("table: '%s' field name: '%s' item name: '%s' ref %p",
+ table_list->alias, name, item_name, ref));
/*
Check that the table and database that qualify the current field name
@@ -6621,9 +5751,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
else
{
if (thd->mark_used_columns == MARK_COLUMNS_READ)
- it->walk(&Item::register_field_in_read_map, 0, (uchar *) 0);
+ it->walk(&Item::register_field_in_read_map, 0, 0);
else
- it->walk(&Item::register_field_in_write_map, 0, (uchar *) 0);
+ it->walk(&Item::register_field_in_write_map, 0, 0);
}
}
else
@@ -6964,6 +6094,8 @@ find_field_in_tables(THD *thd, Item_ident *item,
or as a field name without alias,
or as a field hidden by alias,
or ignoring alias)
+ limit How many items in the list to check
+ (if limit==0 then all items are to be checked)
RETURN VALUES
0 Item is not found or item is not unique,
@@ -6981,9 +6113,10 @@ Item **not_found_item= (Item**) 0x1;
Item **
find_item_in_list(Item *find, List<Item> &items, uint *counter,
find_item_error_report_type report_error,
- enum_resolution_type *resolution)
+ enum_resolution_type *resolution, uint limit)
{
List_iterator<Item> li(items);
+ uint n_items= limit == 0 ? items.elements : limit;
Item **found=0, **found_unaliased= 0, *item;
const char *db_name=0;
const char *field_name=0;
@@ -7007,8 +6140,9 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
db_name= ((Item_ident*) find)->db_name;
}
- for (uint i= 0; (item=li++); i++)
+ for (uint i= 0; i < n_items; i++)
{
+ item= li++;
if (field_name &&
(item->real_item()->type() == Item::FIELD_ITEM ||
((item->type() == Item::REF_ITEM) &&
@@ -7448,7 +6582,6 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
/* Mark field_1 used for table cache. */
bitmap_set_bit(table_1->read_set, field_1->field_index);
table_1->covering_keys.intersect(field_1->part_of_key);
- table_1->merge_keys.merge(field_1->part_of_key);
}
if (field_2)
{
@@ -7456,7 +6589,6 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
/* Mark field_2 used for table cache. */
bitmap_set_bit(table_2->read_set, field_2->field_index);
table_2->covering_keys.intersect(field_2->part_of_key);
- table_2->merge_keys.merge(field_2->part_of_key);
}
if (using_fields != NULL)
@@ -7901,13 +7033,15 @@ 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 wild_num, uint *hidden_bit_fields)
{
+ if (!wild_num)
+ return(0);
+
Item *item;
List_iterator<Item> it(fields);
Query_arena *arena, backup;
DBUG_ENTER("setup_wild");
- DBUG_ASSERT(wild_num != 0);
/*
Don't use arena if we are not in prepared statements or stored procedures
@@ -7940,7 +7074,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
else if (insert_fields(thd, ((Item_field*) item)->context,
((Item_field*) item)->db_name,
((Item_field*) item)->table_name, &it,
- any_privileges))
+ any_privileges, hidden_bit_fields))
{
if (arena)
thd->restore_active_arena(arena, &backup);
@@ -7986,7 +7120,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
** Check that all given fields exists and fill struct with current data
****************************************************************************/
-bool setup_fields(THD *thd, Item **ref_pointer_array,
+bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, enum_mark_columns mark_used_columns,
List<Item> *sum_func_list, List<Item> *pre_fix,
bool allow_sum_func)
@@ -7998,7 +7132,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
bool save_is_item_list_lookup;
bool make_pre_fix= (pre_fix && (pre_fix->elements == 0));
DBUG_ENTER("setup_fields");
- DBUG_PRINT("enter", ("ref_pointer_array: %p", ref_pointer_array));
+ DBUG_PRINT("enter", ("ref_pointer_array: %p", ref_pointer_array.array()));
thd->mark_used_columns= mark_used_columns;
DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
@@ -8020,8 +7154,11 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
TODO: remove it when (if) we made one list for allfields and
ref_pointer_array
*/
- if (ref_pointer_array)
- bzero(ref_pointer_array, sizeof(Item *) * fields.elements);
+ if (!ref_pointer_array.is_null())
+ {
+ DBUG_ASSERT(ref_pointer_array.size() >= fields.elements);
+ memset(ref_pointer_array.array(), 0, sizeof(Item *) * fields.elements);
+ }
/*
We call set_entry() there (before fix_fields() of the whole list of field
@@ -8039,7 +7176,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
while ((var= li++))
var->set_entry(thd, FALSE);
- Item **ref= ref_pointer_array;
+ Ref_ptr_array ref= ref_pointer_array;
thd->lex->current_select->cur_pos_in_select_list= 0;
while ((item= it++))
{
@@ -8055,12 +7192,23 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
DBUG_RETURN(TRUE); /* purecov: inspected */
}
- if (ref)
- *(ref++)= item;
- if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
- sum_func_list)
+ if (!ref.is_null())
+ {
+ ref[0]= item;
+ ref.pop_front();
+ }
+ /*
+ split_sum_func() must be called for Window Function items, see
+ Item_window_func::split_sum_func.
+ */
+ if (sum_func_list &&
+ ((item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) ||
+ item->with_window_func))
+ {
item->split_sum_func(thd, ref_pointer_array, *sum_func_list,
SPLIT_SUM_SELECT);
+ }
+ thd->lex->current_select->select_list_tables|= item->used_tables();
thd->lex->used_tables|= item->used_tables();
thd->lex->current_select->cur_pos_in_select_list++;
}
@@ -8391,13 +7539,13 @@ 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)
+ bool any_privileges, uint *hidden_bit_fields)
{
Field_iterator_table_ref field_iterator;
bool found;
char name_buff[SAFE_NAME_LEN+1];
DBUG_ENTER("insert_fields");
- DBUG_PRINT("arena", ("stmt arena: 0x%lx", (ulong)thd->stmt_arena));
+ DBUG_PRINT("arena", ("stmt arena: %p",thd->stmt_arena));
if (db_name && lower_case_table_names)
{
@@ -8479,7 +7627,10 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
views and natural joins this update is performed inside the loop below.
*/
if (table)
+ {
thd->lex->used_tables|= table->map;
+ thd->lex->current_select->select_list_tables|= table->map;
+ }
/*
Initialize a generic field iterator for the current table reference.
@@ -8508,6 +7659,9 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
else
it->after(item); /* Add 'item' to the SELECT list. */
+ if (item->type() == Item::FIELD_ITEM && item->field_type() == MYSQL_TYPE_BIT)
+ (*hidden_bit_fields)++;
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
Set privilege information for the fields of newly created views.
@@ -8517,7 +7671,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
temporary table. Thus in this case we can be sure that 'item' is an
Item_field.
*/
- if (any_privileges)
+ if (any_privileges && !tables->is_with_table() && !tables->is_derived())
{
DBUG_ASSERT((tables->field_translation == NULL && table) ||
tables->is_natural_join);
@@ -8554,7 +7708,6 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if (table)
{
table->covering_keys.intersect(field->part_of_key);
- table->merge_keys.merge(field->part_of_key);
}
if (tables->is_natural_join)
{
@@ -8571,8 +7724,9 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if (field_table)
{
thd->lex->used_tables|= field_table->map;
+ thd->lex->current_select->select_list_tables|=
+ field_table->map;
field_table->covering_keys.intersect(field->part_of_key);
- field_table->merge_keys.merge(field->part_of_key);
field_table->used_fields++;
}
}
@@ -8819,11 +7973,14 @@ err_no_arena:
@param fields Item_fields list to be filled
@param values values to fill with
@param ignore_errors TRUE if we should ignore errors
+ @param update TRUE if update query
@details
fill_record() may set table->auto_increment_field_not_null and a
caller should make sure that it is reset after their last call to this
function.
+ default functions are executed for inserts.
+ virtual fields are always updated
@return Status
@retval true An error occurred.
@@ -8832,12 +7989,11 @@ err_no_arena:
bool
fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
- bool ignore_errors)
+ bool ignore_errors, bool update)
{
List_iterator_fast<Item> f(fields),v(values);
Item *value, *fld;
Item_field *field;
- TABLE *vcol_table= 0;
bool save_abort_on_warning= thd->abort_on_warning;
bool save_no_errors= thd->no_errors;
DBUG_ENTER("fill_record");
@@ -8863,8 +8019,6 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
table_arg->auto_increment_field_not_null= FALSE;
f.rewind();
}
- else if (thd->lex->unit.insert_table_with_stored_vcol)
- vcol_table= thd->lex->unit.insert_table_with_stored_vcol;
while ((fld= f++))
{
@@ -8879,9 +8033,10 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
if (table->next_number_field &&
rfield->field_index == table->next_number_field->field_index)
table->auto_increment_field_not_null= TRUE;
- if (rfield->vcol_info &&
- value->type() != Item::DEFAULT_VALUE_ITEM &&
- value->type() != Item::NULL_ITEM &&
+ Item::Type type= value->type();
+ if (rfield->vcol_info &&
+ type != Item::DEFAULT_VALUE_ITEM &&
+ type != Item::NULL_ITEM &&
table->s->table_category != TABLE_CATEGORY_TEMPORARY)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
@@ -8889,25 +8044,31 @@ fill_record(THD *thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN),
rfield->field_name, table->s->table_name.str);
}
- if ((!rfield->vcol_info || rfield->stored_in_db) &&
+ if (rfield->stored_in_db() &&
(value->save_in_field(rfield, 0)) < 0 && !ignore_errors)
{
my_message(ER_UNKNOWN_ERROR, ER_THD(thd, ER_UNKNOWN_ERROR), MYF(0));
goto err;
}
- rfield->set_explicit_default(value);
- DBUG_ASSERT(vcol_table == 0 || vcol_table == table);
- vcol_table= table;
+ rfield->set_has_explicit_value();
}
- /* Update virtual fields*/
- thd->abort_on_warning= FALSE;
- if (vcol_table && vcol_table->vfield &&
- update_virtual_fields(thd, vcol_table, VCOL_UPDATE_FOR_WRITE))
+
+ if (update)
+ table_arg->evaluate_update_default_function();
+ else
+ if (table_arg->default_field &&
+ table_arg->update_default_fields(ignore_errors))
+ goto err;
+
+ /* Update virtual fields */
+ if (table_arg->vfield &&
+ table_arg->update_virtual_fields(table_arg->file, VCOL_UPDATE_FOR_WRITE))
goto err;
thd->abort_on_warning= save_abort_on_warning;
thd->no_errors= save_no_errors;
DBUG_RETURN(thd->is_error());
err:
+ DBUG_PRINT("error",("got error"));
thd->abort_on_warning= save_abort_on_warning;
thd->no_errors= save_no_errors;
if (fields.elements)
@@ -8926,19 +8087,48 @@ void switch_to_nullable_trigger_fields(List<Item> &items, TABLE *table)
{
Field** field= table->field_to_fill();
+ /* True if we have NOT NULL fields and BEFORE triggers */
if (field != table->field)
{
List_iterator_fast<Item> it(items);
Item *item;
while ((item= it++))
- item->walk(&Item::switch_to_nullable_fields_processor, 1, (uchar*)field);
+ item->walk(&Item::switch_to_nullable_fields_processor, 1, field);
table->triggers->reset_extra_null_bitmap();
}
}
/**
+ Prepare Virtual fields and field with default expressions to use
+ trigger fields
+
+ This means redirecting from table->field to
+ table->field_to_fill(), if needed.
+*/
+
+void switch_defaults_to_nullable_trigger_fields(TABLE *table)
+{
+ if (!table->default_field)
+ return; // no defaults
+
+ Field **trigger_field= table->field_to_fill();
+
+ /* True if we have NOT NULL fields and BEFORE triggers */
+ if (trigger_field != table->field)
+ {
+ for (Field **field_ptr= table->default_field; *field_ptr ; field_ptr++)
+ {
+ Field *field= (*field_ptr);
+ field->default_value->expr->walk(&Item::switch_to_nullable_fields_processor, 1, trigger_field);
+ *field_ptr= (trigger_field[field->field_index]);
+ }
+ }
+}
+
+
+/**
Test NOT NULL constraint after BEFORE triggers
*/
static bool not_null_fields_have_null_values(TABLE *table)
@@ -8992,36 +8182,37 @@ static bool not_null_fields_have_null_values(TABLE *table)
*/
bool
-fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, List<Item> &fields,
+fill_record_n_invoke_before_triggers(THD *thd, TABLE *table,
+ List<Item> &fields,
List<Item> &values, bool ignore_errors,
enum trg_event_type event)
{
bool result;
Table_triggers_list *triggers= table->triggers;
- result= fill_record(thd, table, fields, values, ignore_errors);
+ result= fill_record(thd, table, fields, values, ignore_errors,
+ event == TRG_EVENT_UPDATE);
if (!result && triggers)
- result= triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, TRUE) ||
- not_null_fields_have_null_values(table);
-
- /*
- Re-calculate virtual fields to cater for cases when base columns are
- updated by the triggers.
- */
- if (!result && triggers)
{
- List_iterator_fast<Item> f(fields);
- Item *fld;
- Item_field *item_field;
- if (fields.elements)
+ if (triggers->process_triggers(thd, event, TRG_ACTION_BEFORE,
+ TRUE) ||
+ not_null_fields_have_null_values(table))
+ return TRUE;
+
+ /*
+ Re-calculate virtual fields to cater for cases when base columns are
+ updated by the triggers.
+ */
+ if (table->vfield && fields.elements)
{
- fld= (Item_field*)f++;
- item_field= fld->field_for_view_update();
- if (item_field && item_field->field && table && table->vfield)
+ Item *fld= (Item_field*) fields.head();
+ Item_field *item_field= fld->field_for_view_update();
+ if (item_field)
{
DBUG_ASSERT(table == item_field->field->table);
- result= update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE);
+ result|= table->update_virtual_fields(table->file,
+ VCOL_UPDATE_FOR_WRITE);
}
}
}
@@ -9031,6 +8222,7 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, List<Item> &fields,
/**
Fill the field buffer of a table with the values of an Item list
+ All fields are given a value
@param thd thread handler
@param table_arg the table that is being modified
@@ -9088,15 +8280,18 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
value=v++;
if (field->field_index == autoinc_index)
table->auto_increment_field_not_null= TRUE;
- if (field->vcol_info &&
- value->type() != Item::DEFAULT_VALUE_ITEM &&
- value->type() != Item::NULL_ITEM &&
- table->s->table_category != TABLE_CATEGORY_TEMPORARY)
+ if (field->vcol_info)
{
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN,
- ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN),
- field->field_name, table->s->table_name.str);
+ Item::Type type= value->type();
+ if (type != Item::DEFAULT_VALUE_ITEM &&
+ type != Item::NULL_ITEM &&
+ table->s->table_category != TABLE_CATEGORY_TEMPORARY)
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN,
+ ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_VIRTUAL_COLUMN),
+ field->field_name, table->s->table_name.str);
+ }
}
if (use_value)
@@ -9104,12 +8299,12 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
else
if (value->save_in_field(field, 0) < 0)
goto err;
- field->set_explicit_default(value);
+ field->set_has_explicit_value();
}
- /* Update virtual fields*/
+ /* Update virtual fields */
thd->abort_on_warning= FALSE;
if (table->vfield &&
- update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE))
+ table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE))
goto err;
thd->abort_on_warning= abort_on_warning_saved;
DBUG_RETURN(thd->is_error());
@@ -9163,7 +8358,7 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, Field **ptr,
{
DBUG_ASSERT(table == (*ptr)->table);
if (table->vfield)
- result= update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE);
+ result= table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE);
}
return result;
@@ -9180,7 +8375,7 @@ my_bool mysql_rm_tmp_tables(void)
THD *thd;
DBUG_ENTER("mysql_rm_tmp_tables");
- if (!(thd= new THD))
+ if (!(thd= new THD(0)))
DBUG_RETURN(1);
thd->thread_stack= (char*) &thd;
thd->store_globals();
@@ -9271,7 +8466,6 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
DBUG_PRINT("info",("Performing FULLTEXT search"));
while ((ifm=li++))
-#if MYSQL_VERSION_ID < 100213
if (unlikely(!ifm->fixed))
/*
it mean that clause where was FT function was removed, so we have
@@ -9279,7 +8473,6 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
*/
li.remove();
else
-#endif
ifm->init_search(thd, no_order);
}
return 0;