diff options
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 160 |
1 files changed, 121 insertions, 39 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 424f572deca..13b8625ebe6 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2010, 2013 Monty Program Ab +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2010, 2015, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -653,6 +653,7 @@ bool close_cached_connection_tables(THD *thd, LEX_STRING *connection) 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) @@ -661,20 +662,25 @@ static void mark_temp_tables_as_free_for_reuse(THD *thd) DBUG_VOID_RETURN; } - 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 (thd->rgi_slave) + rgi_slave=thd->rgi_slave; + if ((!rgi_slave && thd->temporary_tables) || + (rgi_slave && unlikely(rgi_slave->rli->save_temporary_tables))) { - /* - 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; + 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; } @@ -1434,6 +1440,9 @@ unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, bool check_alias) { TABLE_LIST *dup; + + table= table->find_table_for_update(); + if (table->table && table->table->file->ht->db_type == DB_TYPE_MRG_MYISAM) { TABLE_LIST *child; @@ -1544,6 +1553,69 @@ TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl) } +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. + */ + table->file->unbind_psi(); + table->file->rebind_psi(); + } +#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. @@ -1564,26 +1636,6 @@ TABLE *find_temporary_table(THD *thd, if (table->s->table_cache_key.length == table_key_length && !memcmp(table->s->table_cache_key.str, table_key, table_key_length)) { - /* - 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. - */ - table->file->unbind_psi(); - table->file->rebind_psi(); - } -#endif - } result= table; break; } @@ -3404,7 +3456,7 @@ request_backoff_action(enum_open_table_action action_arg, if (action_arg != OT_REOPEN_TABLES && m_has_locks) { my_error(ER_LOCK_DEADLOCK, MYF(0)); - mark_transaction_to_rollback(m_thd, true); + m_thd->mark_transaction_to_rollback(true); return TRUE; } /* @@ -5583,6 +5635,14 @@ TABLE *open_table_uncached(THD *thd, handlerton *hton, (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); @@ -5808,7 +5868,9 @@ bool open_temporary_table(THD *thd, TABLE_LIST *tl) DBUG_RETURN(FALSE); } - if (!(table= find_temporary_table(thd, tl))) + 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) @@ -5819,6 +5881,25 @@ bool open_temporary_table(THD *thd, TABLE_LIST *tl) 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) { @@ -6904,7 +6985,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter, Item_field for tables. */ Item_ident *item_ref= (Item_ident *) item; - if (item_ref->name && item_ref->table_name && + if (field_name && item_ref->name && item_ref->table_name && !my_strcasecmp(system_charset_info, item_ref->name, field_name) && !my_strcasecmp(table_alias_charset, item_ref->table_name, table_name) && @@ -7934,9 +8015,10 @@ bool setup_tables(THD *thd, Name_resolution_context *context, if (select_lex->first_cond_optimization) { leaves.empty(); - if (!select_lex->is_prep_leaf_list_saved) + if (select_lex->prep_leaf_list_state != SELECT_LEX::SAVED) { make_leaves_list(leaves, tables, full_table_list, first_select_table); + select_lex->prep_leaf_list_state= SELECT_LEX::READY; select_lex->leaf_tables_exec.empty(); } else |