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.cc279
1 files changed, 179 insertions, 100 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 5db2d67ac87..e22cc41cd93 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -63,6 +63,9 @@
#include "wsrep_trans_observer.h"
#endif /* WITH_WSREP */
+static bool
+open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
+ TABLE_LIST *tables_end, uint flags);
bool
No_such_table_error_handler::handle_condition(THD *,
@@ -1622,26 +1625,48 @@ bool is_locked_view(THD *thd, TABLE_LIST *t)
}
-bool TABLE::vers_need_hist_part(const THD *thd, const TABLE_LIST *table_list) const
-{
#ifdef WITH_PARTITION_STORAGE_ENGINE
- if (part_info && part_info->part_type == VERSIONING_PARTITION &&
- !table_list->vers_conditions.delete_history &&
- !thd->stmt_arena->is_stmt_prepare() &&
- table_list->lock_type >= TL_WRITE_ALLOW_WRITE &&
- table_list->mdl_request.type >= MDL_SHARED_WRITE &&
- table_list->mdl_request.type < MDL_EXCLUSIVE)
+/**
+ Switch part_info->hist_part and request partition creation if needed.
+
+ @retval true Error or partition creation was requested.
+ @retval false No error
+*/
+bool TABLE::vers_switch_partition(THD *thd, TABLE_LIST *table_list,
+ Open_table_context *ot_ctx)
+{
+ if (!part_info || part_info->part_type != VERSIONING_PARTITION ||
+ table_list->vers_conditions.delete_history ||
+ thd->stmt_arena->is_stmt_prepare() ||
+ table_list->lock_type < TL_WRITE_ALLOW_WRITE ||
+ table_list->mdl_request.type < MDL_SHARED_WRITE ||
+ table_list->mdl_request.type == MDL_EXCLUSIVE)
+ {
+ return false;
+ }
+
+ /*
+ NOTE: we need this condition of prelocking_placeholder because we cannot do
+ auto-create after the transaction is started. Auto-create does
+ close_tables_for_reopen() and that is not possible under started transaction.
+ Also the transaction may not be cancelled at that moment: f.ex. trigger
+ after insert is run when some data is already written.
+
+ We must do auto-creation for PRELOCK_ROUTINE tables at the initial
+ open_tables() no matter what initiating sql_command is.
+ */
+ if (table_list->prelocking_placeholder != TABLE_LIST::PRELOCK_ROUTINE)
{
switch (thd->lex->sql_command)
{
case SQLCOM_INSERT:
if (thd->lex->duplicates != DUP_UPDATE)
- break;
- return true;
+ return false;
+ break;
case SQLCOM_LOAD:
if (thd->lex->duplicates != DUP_REPLACE)
- break;
- return true;
+ return false;
+ break;
case SQLCOM_LOCK_TABLES:
case SQLCOM_DELETE:
case SQLCOM_UPDATE:
@@ -1649,35 +1674,87 @@ bool TABLE::vers_need_hist_part(const THD *thd, const TABLE_LIST *table_list) co
case SQLCOM_REPLACE_SELECT:
case SQLCOM_DELETE_MULTI:
case SQLCOM_UPDATE_MULTI:
- return true;
- default:;
+ break;
+ default:
+ /*
+ TODO: make row events set thd->lex->sql_command appropriately.
+
+ Sergei Golubchik: f.ex. currently row events increment
+ thd->status_var.com_stat[] each event for its own SQLCOM_xxx, it won't be
+ needed if they'll just set thd->lex->sql_command.
+ */
+ if (thd->rgi_slave && thd->rgi_slave->current_event &&
+ thd->lex->sql_command == SQLCOM_END)
+ {
+ switch (thd->rgi_slave->current_event->get_type_code())
+ {
+ case UPDATE_ROWS_EVENT:
+ case UPDATE_ROWS_EVENT_V1:
+ case DELETE_ROWS_EVENT:
+ case DELETE_ROWS_EVENT_V1:
+ break;
+ default:;
+ return false;
+ }
+ }
break;
}
- /*
- TODO: make row events set thd->lex->sql_command appropriately.
+ }
- Sergei Golubchik: f.ex. currently row events increment
- thd->status_var.com_stat[] each event for its own SQLCOM_xxx, it won't be
- needed if they'll just set thd->lex->sql_command.
- */
- if (thd->rgi_slave && thd->rgi_slave->current_event &&
- thd->lex->sql_command == SQLCOM_END)
+ TABLE *table= this;
+
+ /*
+ NOTE: The semantics of vers_set_hist_part() is double: even when we
+ don't need auto-create, we need to update part_info->hist_part.
+ */
+ uint *create_count= table_list->vers_skip_create ?
+ NULL : &ot_ctx->vers_create_count;
+ table_list->vers_skip_create= true;
+ if (table->part_info->vers_set_hist_part(thd, create_count))
+ {
+ MYSQL_UNBIND_TABLE(table->file);
+ tc_release_table(table);
+ return true;
+ }
+ if (ot_ctx->vers_create_count)
+ {
+ Open_table_context::enum_open_table_action action;
+ TABLE_LIST *table_arg;
+ mysql_mutex_lock(&table->s->LOCK_share);
+ if (!table->s->vers_skip_auto_create)
{
- switch (thd->rgi_slave->current_event->get_type_code())
- {
- case UPDATE_ROWS_EVENT:
- case UPDATE_ROWS_EVENT_V1:
- case DELETE_ROWS_EVENT:
- case DELETE_ROWS_EVENT_V1:
- return true;
- default:;
- break;
- }
+ table->s->vers_skip_auto_create= true;
+ action= Open_table_context::OT_ADD_HISTORY_PARTITION;
+ table_arg= table_list;
}
+ else
+ {
+ /*
+ NOTE: this may repeat multiple times until creating thread acquires
+ MDL_EXCLUSIVE. Since auto-creation is rare operation this is acceptable.
+ We could suspend this thread on cond-var but we must first exit
+ MDL_SHARED_WRITE first and we cannot store cond-var into TABLE_SHARE
+ because it is already released and there is no guarantee that it will
+ be same instance if we acquire it again.
+ */
+ table_list->vers_skip_create= false;
+ ot_ctx->vers_create_count= 0;
+ action= Open_table_context::OT_REOPEN_TABLES;
+ table_arg= NULL;
+ }
+ mysql_mutex_unlock(&table->s->LOCK_share);
+ if (!thd->locked_tables_mode)
+ {
+ MYSQL_UNBIND_TABLE(table->file);
+ tc_release_table(table);
+ }
+ ot_ctx->request_backoff_action(action, table_arg);
+ return true;
}
-#endif
+
return false;
}
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
/**
@@ -1832,14 +1909,8 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
DBUG_PRINT("info",("Using locked table"));
#ifdef WITH_PARTITION_STORAGE_ENGINE
part_names_error= set_partitions_as_used(table_list, table);
- if (table->vers_need_hist_part(thd, table_list))
- {
- /*
- New partitions are not auto-created under LOCK TABLES (TODO: fix it)
- but rotation can still happen.
- */
- (void) table->part_info->vers_set_hist_part(thd, NULL);
- }
+ if (table->vers_switch_partition(thd, table_list, ot_ctx))
+ DBUG_RETURN(true);
#endif
goto reset;
}
@@ -2095,54 +2166,10 @@ retry_share:
tc_add_table(thd, table);
}
- if (table->vers_need_hist_part(thd, table_list))
- {
- /*
- NOTE: The semantics of vers_set_hist_part() is double: even when we
- don't need auto-create, we need to update part_info->hist_part.
- */
- uint *create_count= table_list->vers_skip_create ?
- NULL : &ot_ctx->vers_create_count;
- table_list->vers_skip_create= true;
- if (table->part_info->vers_set_hist_part(thd, create_count))
- {
- MYSQL_UNBIND_TABLE(table->file);
- tc_release_table(table);
- DBUG_RETURN(TRUE);
- }
- if (ot_ctx->vers_create_count)
- {
- Open_table_context::enum_open_table_action action;
- TABLE_LIST *table_arg;
- mysql_mutex_lock(&table->s->LOCK_share);
- if (!table->s->vers_skip_auto_create)
- {
- table->s->vers_skip_auto_create= true;
- action= Open_table_context::OT_ADD_HISTORY_PARTITION;
- table_arg= table_list;
- }
- else
- {
- /*
- NOTE: this may repeat multiple times until creating thread acquires
- MDL_EXCLUSIVE. Since auto-creation is rare operation this is acceptable.
- We could suspend this thread on cond-var but we must first exit
- MDL_SHARED_WRITE first and we cannot store cond-var into TABLE_SHARE
- because it is already released and there is no guarantee that it will
- be same instance if we acquire it again.
- */
- table_list->vers_skip_create= false;
- ot_ctx->vers_create_count= 0;
- action= Open_table_context::OT_REOPEN_TABLES;
- table_arg= NULL;
- }
- mysql_mutex_unlock(&table->s->LOCK_share);
- MYSQL_UNBIND_TABLE(table->file);
- tc_release_table(table);
- ot_ctx->request_backoff_action(action, table_arg);
- DBUG_RETURN(TRUE);
- }
- }
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (table->vers_switch_partition(thd, table_list, ot_ctx))
+ DBUG_RETURN(true);
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
if (!(flags & MYSQL_OPEN_HAS_MDL_LOCK) &&
table->s->table_category < TABLE_CATEGORY_INFORMATION)
@@ -3291,8 +3318,14 @@ Open_table_context::recover_from_failed_open()
case OT_DISCOVER:
case OT_REPAIR:
case OT_ADD_HISTORY_PARTITION:
- result= lock_table_names(m_thd, m_thd->lex->create_info, m_failed_table,
- NULL, get_timeout(), 0);
+ if (!m_thd->locked_tables_mode)
+ result= lock_table_names(m_thd, m_thd->lex->create_info, m_failed_table,
+ NULL, get_timeout(), 0);
+ else
+ {
+ DBUG_ASSERT(!result);
+ DBUG_ASSERT(m_action == OT_ADD_HISTORY_PARTITION);
+ }
/*
We are now under MDL_EXCLUSIVE mode. Other threads have no table share
acquired: they are blocked either at open_table_get_mdl_lock() in
@@ -3320,8 +3353,13 @@ Open_table_context::recover_from_failed_open()
break;
}
- tdc_remove_table(m_thd, m_failed_table->db.str,
- m_failed_table->table_name.str);
+ /*
+ We don't need to remove share under OT_ADD_HISTORY_PARTITION.
+ Moreover fast_alter_partition_table() works with TABLE instance.
+ */
+ if (m_action != OT_ADD_HISTORY_PARTITION)
+ tdc_remove_table(m_thd, m_failed_table->db.str,
+ m_failed_table->table_name.str);
switch (m_action)
{
@@ -3361,12 +3399,56 @@ Open_table_context::recover_from_failed_open()
}
DBUG_ASSERT(vers_create_count);
- TABLE_LIST *tl= m_failed_table;
- result= vers_create_partitions(m_thd, tl, vers_create_count);
+ result= vers_create_partitions(m_thd, m_failed_table, vers_create_count);
+ vers_create_count= 0;
if (!m_thd->transaction->stmt.is_empty())
trans_commit_stmt(m_thd);
- close_tables_for_reopen(m_thd, &tl, start_of_statement_svp());
- vers_create_count= 0;
+ DBUG_ASSERT(!result ||
+ !m_thd->locked_tables_mode ||
+ m_thd->lock->lock_count);
+ if (result)
+ break;
+ if (!m_thd->locked_tables_mode)
+ {
+ /*
+ alter_partition_lock_handling() does mysql_lock_remove() but
+ does not clear thd->lock completely.
+ */
+ DBUG_ASSERT(m_thd->lock->lock_count == 0);
+ if (!(m_thd->lock->flags & GET_LOCK_ON_THD))
+ my_free(m_thd->lock);
+ m_thd->lock= NULL;
+ }
+ else if (m_thd->locked_tables_mode == LTM_PRELOCKED)
+ {
+ MYSQL_LOCK *lock;
+ MYSQL_LOCK *merged_lock;
+
+ /*
+ In LTM_LOCK_TABLES table was reopened via locked_tables_list,
+ but not in prelocked environment where we have to reopen
+ the table manually.
+ */
+ Open_table_context ot_ctx(m_thd, MYSQL_OPEN_REOPEN);
+ if (open_table(m_thd, m_failed_table, &ot_ctx))
+ {
+ result= true;
+ break;
+ }
+ TABLE *table= m_failed_table->table;
+ table->reginfo.lock_type= m_thd->update_lock_default;
+ m_thd->in_lock_tables= 1;
+ lock= mysql_lock_tables(m_thd, &table, 1,
+ MYSQL_OPEN_REOPEN | MYSQL_LOCK_USE_MALLOC);
+ m_thd->in_lock_tables= 0;
+ if (lock == NULL ||
+ !(merged_lock= mysql_lock_merge(m_thd->lock, lock, m_thd)))
+ {
+ result= true;
+ break;
+ }
+ m_thd->lock= merged_lock;
+ }
break;
}
case OT_BACKOFF_AND_RETRY:
@@ -5309,9 +5391,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
if (table_list->table)
DBUG_RETURN(table_list->table);
- /* should not be used in a prelocked_mode context, see NOTE above */
- DBUG_ASSERT(thd->locked_tables_mode < LTM_PRELOCKED);
-
THD_STAGE_INFO(thd, stage_opening_tables);
thd->current_tablenr= 0;
/* open_ltable can be used only for BASIC TABLEs */