diff options
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 955 |
1 files changed, 16 insertions, 939 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e6f8b291778..e14fb1b4e5f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -172,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 @@ -304,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) @@ -602,96 +568,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) -{ - rpl_group_info *rgi_slave; - 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; - } - - rgi_slave=thd->rgi_slave; - if ((!rgi_slave && thd->temporary_tables) || - (rgi_slave && unlikely(rgi_slave->rli->save_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(); - if (rgi_slave) - { - /* - Temporary tables are shared with other by sql execution threads. - As a safety messure, clear the pointer to the common area. - */ - thd->temporary_tables= 0; - } - } - 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. @@ -894,7 +770,7 @@ void close_thread_tables(THD *thd) /* 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) { @@ -1008,196 +884,6 @@ void close_thread_table(THD *thd, TABLE **table_ptr) } -/* 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); - - /* 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 (; - table && is_user_table(table) && - (ulong) tmpkeyval(thd, table) == - (ulong) thd->variables.pseudo_thread_id && - table->s->db.length == db.length() && - memcmp(table->s->db.str, db.ptr(), db.length()) == 0; - table= next) - { - /* - 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); - } - 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); - 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. @@ -1470,291 +1156,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(); - 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(); - 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)); - - closefrm(table); - 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. @@ -1819,7 +1220,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); @@ -3935,7 +3336,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables, 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. @@ -3951,7 +3352,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables, 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); @@ -3970,7 +3371,8 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables, 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); @@ -3986,7 +3388,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables, 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) @@ -4158,6 +3560,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. @@ -4360,6 +3763,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()"). @@ -4533,7 +3937,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; @@ -4595,7 +3999,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; @@ -5050,7 +4454,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); @@ -5137,8 +4541,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). @@ -5533,176 +4938,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(); - } - 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 @@ -5771,164 +5006,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. |