summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2013-12-16 13:02:21 +0100
committerSergei Golubchik <sergii@pisem.net>2013-12-16 13:02:21 +0100
commitd28d3ba40dc8ebef87199a2567ec96e9c5d744e2 (patch)
treec6b9ab1d8193fa2a26c5e376d43e536abd3a47ce /sql
parentff485d2dc4d5adaf5eef0ccd03ce62adf3bd30b3 (diff)
parent6bf10fac445d73fb796d4863612c87bff5f28b66 (diff)
downloadmariadb-git-d28d3ba40dc8ebef87199a2567ec96e9c5d744e2.tar.gz
10.0-base merge
Diffstat (limited to 'sql')
-rw-r--r--sql/event_scheduler.cc66
-rw-r--r--sql/event_scheduler.h2
-rw-r--r--sql/events.cc7
-rw-r--r--sql/events.h2
-rw-r--r--sql/ha_ndbcluster_binlog.cc8
-rw-r--r--sql/ha_partition.cc2
-rw-r--r--sql/handler.cc12
-rw-r--r--sql/item.cc48
-rw-r--r--sql/item.h11
-rw-r--r--sql/item_cmpfunc.cc43
-rw-r--r--sql/item_cmpfunc.h7
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_func.h5
-rw-r--r--sql/item_sum.cc2
-rw-r--r--sql/item_timefunc.cc25
-rw-r--r--sql/item_timefunc.h4
-rw-r--r--sql/log.cc311
-rw-r--r--sql/log.h7
-rw-r--r--sql/log_event.cc12
-rw-r--r--sql/log_event_old.cc5
-rw-r--r--sql/mysqld.cc114
-rw-r--r--sql/mysqld.h4
-rw-r--r--sql/opt_range.cc9
-rw-r--r--sql/opt_subselect.cc20
-rw-r--r--sql/opt_table_elimination.cc15
-rw-r--r--sql/partition_info.cc5
-rw-r--r--sql/rpl_gtid.cc193
-rw-r--r--sql/rpl_gtid.h5
-rw-r--r--sql/rpl_rli.cc13
-rw-r--r--sql/rpl_utility.cc23
-rw-r--r--sql/slave.cc16
-rw-r--r--sql/sp_head.cc35
-rw-r--r--sql/sql_admin.cc16
-rw-r--r--sql/sql_base.cc48
-rw-r--r--sql/sql_base.h6
-rw-r--r--sql/sql_cache.cc11
-rw-r--r--sql/sql_class.cc4
-rw-r--r--sql/sql_class.h12
-rw-r--r--sql/sql_db.cc5
-rw-r--r--sql/sql_handler.cc3
-rw-r--r--sql/sql_lex.cc3
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_manager.cc9
-rw-r--r--sql/sql_parse.cc47
-rw-r--r--sql/sql_prepare.cc21
-rw-r--r--sql/sql_repl.cc4
-rw-r--r--sql/sql_select.cc118
-rw-r--r--sql/sql_show.cc8
-rw-r--r--sql/sql_table.cc55
-rw-r--r--sql/sql_time.cc19
-rw-r--r--sql/sql_time.h1
-rw-r--r--sql/sql_union.cc18
-rw-r--r--sql/sql_view.cc2
-rw-r--r--sql/sys_vars.cc8
-rw-r--r--sql/table.cc6
-rw-r--r--sql/transaction.cc50
-rw-r--r--sql/transaction.h1
-rw-r--r--sql/tztime.cc44
58 files changed, 1105 insertions, 449 deletions
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index f75a8abc835..92093e34b81 100644
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -239,6 +239,12 @@ event_scheduler_thread(void *arg)
my_free(arg);
if (!res)
scheduler->run(thd);
+ else
+ {
+ thd->proc_info= "Clearing";
+ net_end(&thd->net);
+ delete thd;
+ }
DBUG_LEAVE; // Against gcc warnings
my_thread_end();
@@ -366,26 +372,26 @@ Event_scheduler::~Event_scheduler()
}
-/*
+/**
Starts the scheduler (again). Creates a new THD and passes it to
a forked thread. Does not wait for acknowledgement from the new
thread that it has started. Asynchronous starting. Most of the
needed initializations are done in the current thread to minimize
the chance of failure in the spawned thread.
- SYNOPSIS
- Event_scheduler::start()
+ @param[out] err_no - errno indicating type of error which caused
+ failure to start scheduler thread.
- RETURN VALUE
- FALSE OK
- TRUE Error (not reported)
+ @return
+ @retval false Success.
+ @retval true Error.
*/
bool
-Event_scheduler::start()
+Event_scheduler::start(int *err_no)
{
THD *new_thd= NULL;
- bool ret= FALSE;
+ bool ret= false;
pthread_t th;
struct scheduler_param *scheduler_param_value;
DBUG_ENTER("Event_scheduler::start");
@@ -398,7 +404,7 @@ Event_scheduler::start()
if (!(new_thd= new THD))
{
sql_print_error("Event Scheduler: Cannot initialize the scheduler thread");
- ret= TRUE;
+ ret= true;
goto end;
}
@@ -427,21 +433,30 @@ Event_scheduler::start()
DBUG_PRINT("info", ("Setting state go RUNNING"));
state= RUNNING;
DBUG_PRINT("info", ("Forking new thread for scheduler. THD: 0x%lx", (long) new_thd));
- if (mysql_thread_create(key_thread_event_scheduler,
- &th, &connection_attrib, event_scheduler_thread,
- (void*)scheduler_param_value))
+ if ((*err_no= mysql_thread_create(key_thread_event_scheduler,
+ &th, &connection_attrib,
+ event_scheduler_thread,
+ (void*)scheduler_param_value)))
{
DBUG_PRINT("error", ("cannot create a new thread"));
+ sql_print_error("Event scheduler: Failed to start scheduler,"
+ " Can not create thread for event scheduler (errno=%d)",
+ *err_no);
+
+ new_thd->proc_info= "Clearing";
+ DBUG_ASSERT(new_thd->net.buff != 0);
+ net_end(&new_thd->net);
+
state= INITIALIZED;
scheduler_thd= NULL;
- ret= TRUE;
+ delete new_thd;
- new_thd->proc_info= "Clearing";
- delete_running_thd(new_thd);
+ delete scheduler_param_value;
+ ret= true;
}
+
end:
UNLOCK_DATA();
-
DBUG_RETURN(ret);
}
@@ -553,7 +568,20 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name)
if ((res= mysql_thread_create(key_thread_event_worker,
&th, &connection_attrib, event_worker_thread,
event_name)))
+ {
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ Events::opt_event_scheduler= Events::EVENTS_OFF;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+
+ sql_print_error("Event_scheduler::execute_top: Can not create event worker"
+ " thread (errno=%d). Stopping event scheduler", res);
+
+ new_thd->proc_info= "Clearing";
+ DBUG_ASSERT(new_thd->net.buff != 0);
+ net_end(&new_thd->net);
+
goto error;
+ }
started_events++;
executed_events++; // For SHOW STATUS
@@ -564,10 +592,8 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name)
error:
DBUG_PRINT("error", ("Event_scheduler::execute_top() res: %d", res));
if (new_thd)
- {
- new_thd->proc_info= "Clearing";
- delete_running_thd(new_thd);
- }
+ delete new_thd;
+
delete event_name;
DBUG_RETURN(TRUE);
}
diff --git a/sql/event_scheduler.h b/sql/event_scheduler.h
index 0b160ff49d5..4f6b9349162 100644
--- a/sql/event_scheduler.h
+++ b/sql/event_scheduler.h
@@ -78,7 +78,7 @@ public:
/* State changing methods follow */
bool
- start();
+ start(int *err_no);
bool
stop();
diff --git a/sql/events.cc b/sql/events.cc
index acf842dea44..040b73730e9 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -791,6 +791,7 @@ Events::init(bool opt_noacl_or_bootstrap)
{
THD *thd;
+ int err_no;
bool res= FALSE;
DBUG_ENTER("Events::init");
@@ -871,7 +872,7 @@ Events::init(bool opt_noacl_or_bootstrap)
}
if (event_queue->init_queue(thd) || load_events_from_db(thd) ||
- (opt_event_scheduler == EVENTS_ON && scheduler->start()))
+ (opt_event_scheduler == EVENTS_ON && scheduler->start(&err_no)))
{
sql_print_error("Event Scheduler: Error while loading from disk.");
res= TRUE; /* fatal error: request unireg_abort */
@@ -1033,9 +1034,9 @@ Events::dump_internal_status()
DBUG_VOID_RETURN;
}
-bool Events::start()
+bool Events::start(int *err_no)
{
- return scheduler->start();
+ return scheduler->start(err_no);
}
bool Events::stop()
diff --git a/sql/events.h b/sql/events.h
index 4720c301052..a6480e7241d 100644
--- a/sql/events.h
+++ b/sql/events.h
@@ -83,7 +83,7 @@ public:
/* Protected using LOCK_global_system_variables only. */
static ulong opt_event_scheduler;
static bool check_if_system_tables_error();
- static bool start();
+ static bool start(int *err_no);
static bool stop();
public:
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index 813c750053a..fc53183ca7a 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2006, 2011, Oracle and/or its affiliates.
+/* Copyright (c) 2006, 2013, Oracle and/or its affiliates.
Copyright (c) 2012, 2013, Monty Proram Ab.
This program is free software; you can redistribute it and/or modify
@@ -2408,6 +2408,12 @@ add_ndb_binlog_index_err:
thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
thd->get_stmt_da()->set_overwrite_status(false);
close_thread_tables(thd);
+ /*
+ There should be no need for rolling back transaction due to deadlock
+ (since ndb_binlog_index is non transactional).
+ */
+ DBUG_ASSERT(! thd->transaction_rollback_request);
+
thd->mdl_context.release_transactional_locks();
ndb_binlog_index= 0;
thd->variables.option_bits= saved_options;
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index fd6d89dd7ff..603e0bf59dc 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -6648,7 +6648,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_STATS *stat_info,
{
handler *file= m_file[part_id];
DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), part_id));
- file->info(HA_STATUS_CONST | HA_STATUS_TIME | HA_STATUS_VARIABLE |
+ file->info(HA_STATUS_TIME | HA_STATUS_VARIABLE |
HA_STATUS_VARIABLE_EXTRA | HA_STATUS_NO_LOCK);
stat_info->records= file->stats.records;
diff --git a/sql/handler.cc b/sql/handler.cc
index 075855bde16..ae337f4a153 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1587,10 +1587,16 @@ int ha_rollback_trans(THD *thd, bool all)
}
trans->ha_list= 0;
trans->no_2pc=0;
- if (is_real_trans && thd->transaction_rollback_request &&
- thd->transaction.xid_state.xa_state != XA_NOTR)
- thd->transaction.xid_state.rm_error= thd->get_stmt_da()->sql_errno();
}
+
+ /*
+ Thanks to possibility of MDL deadlock rollback request can come even if
+ transaction hasn't been started in any transactional storage engine.
+ */
+ if (is_real_trans && thd->transaction_rollback_request &&
+ thd->transaction.xid_state.xa_state != XA_NOTR)
+ thd->transaction.xid_state.rm_error= thd->get_stmt_da()->sql_errno();
+
/* Always cleanup. Even if nht==0. There may be savepoints. */
if (is_real_trans)
{
diff --git a/sql/item.cc b/sql/item.cc
index 38f5ed6bf5c..5bc9d5816eb 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -8921,6 +8921,18 @@ Item_cache_temporal::Item_cache_temporal(enum_field_types field_type_arg):
}
+longlong Item_cache_temporal::val_temporal_packed()
+{
+ DBUG_ASSERT(fixed == 1);
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= TRUE;
+ return 0;
+ }
+ return value;
+}
+
+
String *Item_cache_temporal::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -8933,6 +8945,42 @@ String *Item_cache_temporal::val_str(String *str)
}
+my_decimal *Item_cache_temporal::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= true;
+ return NULL;
+ }
+ return val_decimal_from_date(decimal_value);
+}
+
+
+longlong Item_cache_temporal::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= true;
+ return 0;
+ }
+ return val_int_from_date();
+}
+
+
+double Item_cache_temporal::val_real()
+{
+ DBUG_ASSERT(fixed == 1);
+ if ((!value_cached && !cache_value()) || null_value)
+ {
+ null_value= true;
+ return 0;
+ }
+ return val_real_from_date();
+}
+
+
bool Item_cache_temporal::cache_value()
{
if (!example)
diff --git a/sql/item.h b/sql/item.h
index f5917f7d9c3..6afeca66f0a 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -3410,13 +3410,16 @@ class Item_direct_view_ref :public Item_direct_ref
TABLE_LIST *view;
TABLE *null_ref_table;
+#define NO_NULL_TABLE (reinterpret_cast<TABLE *>(0x1))
+
bool check_null_ref()
{
if (null_ref_table == NULL)
{
- null_ref_table= view->get_real_join_table();
+ if (!(null_ref_table= view->get_real_join_table()))
+ null_ref_table= NO_NULL_TABLE;
}
- if (null_ref_table->null_row)
+ if (null_ref_table != NO_NULL_TABLE && null_ref_table->null_row)
{
null_value= 1;
return TRUE;
@@ -4271,6 +4274,10 @@ class Item_cache_temporal: public Item_cache_int
public:
Item_cache_temporal(enum_field_types field_type_arg);
String* val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
+ longlong val_int();
+ longlong val_temporal_packed();
+ double val_real();
bool cache_value();
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
int save_in_field(Field *field, bool no_conversions);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 714eb8be7ee..bc0990d50b2 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -888,10 +888,13 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
enum_field_types f_type= item->cmp_type() == TIME_RESULT ?
item->field_type() : warn_item->field_type();
- if (item->result_type() == INT_RESULT && item->cmp_type() == TIME_RESULT)
+ if (item->result_type() == INT_RESULT &&
+ item->cmp_type() == TIME_RESULT &&
+ item->type() == Item::CACHE_ITEM)
{
/* it's our Item_cache_temporal, as created below */
- value= item->val_int();
+ DBUG_ASSERT(is_temporal_type(((Item_cache *) item)->field_type()));
+ value= ((Item_cache_temporal*) item)->val_temporal_packed();
}
else
{
@@ -5706,8 +5709,8 @@ Item *Item_bool_rowready_func2::negated_item()
*/
Item_equal::Item_equal(Item *f1, Item *f2, bool with_const_item)
- : Item_bool_func(), eval_item(0), cond_false(0), context_field(NULL),
- link_equal_fields(FALSE)
+ : Item_bool_func(), eval_item(0), cond_false(0), cond_true(0),
+ context_field(NULL), link_equal_fields(FALSE)
{
const_item_cache= 0;
with_const= with_const_item;
@@ -5732,8 +5735,8 @@ Item_equal::Item_equal(Item *f1, Item *f2, bool with_const_item)
*/
Item_equal::Item_equal(Item_equal *item_equal)
- : Item_bool_func(), eval_item(0), cond_false(0), context_field(NULL),
- link_equal_fields(FALSE)
+ : Item_bool_func(), eval_item(0), cond_false(0), cond_true(0),
+ context_field(NULL), link_equal_fields(FALSE)
{
const_item_cache= 0;
List_iterator_fast<Item> li(item_equal->equal_items);
@@ -5800,13 +5803,9 @@ void Item_equal::add_const(Item *c, Item *f)
func->quick_fix_field();
cond_false= !func->val_int();
}
- /*
- TODO: also support the case where Item_equal becomes singular with
- this->is_cond_true()=1. When I attempted to mark the item as constant,
- the optimizer attempted to remove it, however it is still referenced from
- COND_EQUAL and I got a crash.
- */
- if (cond_false)
+ if (with_const && equal_items.elements == 1)
+ cond_true= TRUE;
+ if (cond_false || cond_true)
const_item_cache= 1;
}
@@ -6010,8 +6009,7 @@ void Item_equal::merge_into_list(List<Item_equal> *list,
void Item_equal::sort(Item_field_cmpfunc compare, void *arg)
{
- if (equal_items.elements > 1)
- bubble_sort<Item>(&equal_items, compare, arg);
+ bubble_sort<Item>(&equal_items, compare, arg);
}
@@ -6139,13 +6137,7 @@ bool Item_equal::fix_fields(THD *thd, Item **ref)
void Item_equal::update_used_tables()
{
not_null_tables_cache= used_tables_cache= 0;
- /*
- TODO: also support the case where Item_equal becomes singular with
- this->is_cond_true()=1. When I attempted to mark the item as constant,
- the optimizer attempted to remove it, however it is still referenced from
- COND_EQUAL and I got a crash.
- */
- if ((const_item_cache= cond_false))
+ if ((const_item_cache= cond_false || cond_true))
return;
Item_equal_fields_iterator it(*this);
Item *item;
@@ -6194,7 +6186,7 @@ longlong Item_equal::val_int()
{
if (cond_false)
return 0;
- if (is_cond_true())
+ if (cond_true)
return 1;
Item *item= get_const();
Item_equal_fields_iterator it(*this);
@@ -6220,11 +6212,6 @@ longlong Item_equal::val_int()
void Item_equal::fix_length_and_dec()
{
Item *item= get_first(NO_PARTICULAR_TAB, NULL);
- if (!item)
- {
- DBUG_ASSERT(is_cond_true()); // it should be the only constant
- item= equal_items.head();
- }
eval_item= cmp_item::get_comparator(item->cmp_type(), item,
item->collation.collation);
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index a438139bcfe..a0d9b7c20fa 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1794,6 +1794,12 @@ class Item_equal: public Item_bool_func
the equal_items should be ignored.
*/
bool cond_false;
+ /*
+ This initially is set to FALSE. It becomes TRUE when this item is evaluated
+ as being always true. If the flag is TRUE the contents of the list
+ the equal_items should be ignored.
+ */
+ bool cond_true;
/*
compare_as_dates=TRUE <-> constants equal to fields from equal_items
must be compared as datetimes and not as strings.
@@ -1826,7 +1832,6 @@ public:
Item_equal(Item_equal *item_equal);
/* Currently the const item is always the first in the list of equal items */
inline Item* get_const() { return with_const ? equal_items.head() : NULL; }
- inline bool is_cond_true() { return equal_items.elements == 1; }
void add_const(Item *c, Item *f = NULL);
/** Add a non-constant item to the multiple equality */
void add(Item *f) { equal_items.push_back(f); }
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 36edc3aee55..f9f467f44f3 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -824,6 +824,8 @@ void Item_num_op::find_num_type(void)
cached_result_type= DECIMAL_RESULT;
result_precision();
fix_decimals();
+ if ((r0 == TIME_RESULT || r1 == TIME_RESULT) && decimals == 0)
+ cached_result_type= INT_RESULT;
}
else
{
diff --git a/sql/item_func.h b/sql/item_func.h
index 03e67ddf11a..4b1516dcc4d 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -167,7 +167,10 @@ public:
Item **item, uint nitems);
inline bool get_arg0_time(MYSQL_TIME *ltime)
{
- return (null_value=args[0]->get_time(ltime));
+ null_value= args[0]->get_time(ltime);
+ DBUG_ASSERT(null_value ||
+ ltime->time_type != MYSQL_TIMESTAMP_TIME || ltime->day == 0);
+ return null_value;
}
bool is_null() {
update_null_value();
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index b3be7339849..367ff39eab6 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1266,7 +1266,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
void Item_sum_hybrid::setup_hybrid(Item *item, Item *value_arg)
{
- if (!(value= Item_cache::get_cache(item)))
+ if (!(value= Item_cache::get_cache(item, item->cmp_type())))
return;
value->setup(item);
value->store(value_arg);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 6eaeec0804f..6ffa8b2af46 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1480,27 +1480,6 @@ String *Item_temporal_func::val_str(String *str)
}
-longlong Item_temporal_func::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_date(&ltime, sql_mode))
- return 0;
- longlong v= TIME_to_ulonglong(&ltime);
- return ltime.neg ? -v : v;
-}
-
-
-double Item_temporal_func::val_real()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_date(&ltime, sql_mode))
- return 0;
- return TIME_to_double(&ltime);
-}
-
-
String *Item_temporal_hybrid_func::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -2185,6 +2164,10 @@ longlong Item_extract::val_int()
return 0;
neg= ltime.neg ? -1 : 1;
+ DBUG_ASSERT(ltime.time_type != MYSQL_TIMESTAMP_TIME || ltime.day == 0);
+ if (ltime.time_type == MYSQL_TIMESTAMP_TIME)
+ time_to_daytime_interval(&ltime);
+
switch (int_type) {
case INTERVAL_YEAR: return ltime.year;
case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month;
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 76f84b88795..cdf03199a81 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -498,8 +498,8 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
Item_result cmp_type() const { return TIME_RESULT; }
String *val_str(String *str);
- longlong val_int();
- double val_real();
+ longlong val_int() { return val_int_from_date(); }
+ double val_real() { return val_real_from_date(); }
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date) { DBUG_ASSERT(0); return 1; }
my_decimal *val_decimal(my_decimal *decimal_value)
{ return val_decimal_from_date(decimal_value); }
diff --git a/sql/log.cc b/sql/log.cc
index 6f08a924116..90305ec227e 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2953,7 +2953,8 @@ MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period)
bytes_written(0), file_id(1), open_count(1),
group_commit_queue(0), group_commit_queue_busy(FALSE),
num_commits(0), num_group_commits(0),
- sync_period_ptr(sync_period), sync_counter(0), state_read(false),
+ sync_period_ptr(sync_period), sync_counter(0),
+ state_file_deleted(false), binlog_state_recover_done(false),
is_relay_log(0), signal_cnt(0),
checksum_alg_reset(BINLOG_CHECKSUM_ALG_UNDEF),
relay_log_checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF),
@@ -3155,12 +3156,19 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
DBUG_ENTER("MYSQL_BIN_LOG::open");
DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
- if (!is_relay_log && read_state_from_file())
- DBUG_RETURN(1);
+ if (!is_relay_log)
+ {
+ if (!binlog_state_recover_done)
+ {
+ binlog_state_recover_done= true;
+ if (do_binlog_recovery(opt_bin_logname, false))
+ DBUG_RETURN(1);
+ }
- if (!is_relay_log && !binlog_background_thread_started &&
- start_binlog_background_thread())
- DBUG_RETURN(1);
+ if (!binlog_background_thread_started &&
+ start_binlog_background_thread())
+ DBUG_RETURN(1);
+ }
if (init_and_set_log_file_name(log_name, new_name, log_type_arg,
io_cache_type_arg))
@@ -3447,6 +3455,25 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
my_free(binlog_xid_count_list.get());
binlog_xid_count_list.push_back(new_xid_list_entry);
mysql_mutex_unlock(&LOCK_xid_list);
+
+ /*
+ Now that we have synced a new binlog file with an initial Gtid_list
+ event, it is safe to delete the binlog state file. We will write out
+ a new, updated file at shutdown, and if we crash before we can recover
+ the state from the newly written binlog file.
+
+ Since the state file will contain out-of-date data as soon as the first
+ new GTID is binlogged, it is better to remove it, to avoid any risk of
+ accidentally reading incorrect data later.
+ */
+ if (!state_file_deleted)
+ {
+ char buf[FN_REFLEN];
+ fn_format(buf, opt_bin_logname, mysql_data_home, ".state",
+ MY_UNPACK_FILENAME);
+ my_delete(buf, MY_SYNC_DIR);
+ state_file_deleted= true;
+ }
}
log_state= LOG_OPENED;
@@ -5422,19 +5449,15 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone,
gtid.domain_id= domain_id;
gtid.server_id= server_id;
gtid.seq_no= seq_no;
- mysql_mutex_lock(&LOCK_rpl_gtid_state);
err= rpl_global_gtid_binlog_state.update(&gtid, opt_gtid_strict_mode);
- mysql_mutex_unlock(&LOCK_rpl_gtid_state);
if (err && thd->get_stmt_da()->sql_errno()==ER_GTID_STRICT_OUT_OF_ORDER)
errno= ER_GTID_STRICT_OUT_OF_ORDER;
}
else
{
/* Allocate the next sequence number for the GTID. */
- mysql_mutex_lock(&LOCK_rpl_gtid_state);
err= rpl_global_gtid_binlog_state.update_with_next_gtid(domain_id,
server_id, &gtid);
- mysql_mutex_unlock(&LOCK_rpl_gtid_state);
seq_no= gtid.seq_no;
}
if (err)
@@ -5508,10 +5531,6 @@ MYSQL_BIN_LOG::read_state_from_file()
bool opened= false;
bool inited= false;
- if (state_read)
- return 0;
- state_read= true;
-
fn_format(buf, opt_bin_logname, mysql_data_home, ".state",
MY_UNPACK_FILENAME);
if ((file_no= mysql_file_open(key_file_binlog_state, buf,
@@ -5564,36 +5583,21 @@ MYSQL_BIN_LOG::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size)
bool
MYSQL_BIN_LOG::append_state_pos(String *str)
{
- bool err;
-
- mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
- err= rpl_global_gtid_binlog_state.append_pos(str);
- mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
- return err;
+ return rpl_global_gtid_binlog_state.append_pos(str);
}
bool
MYSQL_BIN_LOG::append_state(String *str)
{
- bool err;
-
- mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
- err= rpl_global_gtid_binlog_state.append_state(str);
- mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
- return err;
+ return rpl_global_gtid_binlog_state.append_state(str);
}
bool
MYSQL_BIN_LOG::is_empty_state()
{
- bool res;
-
- mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
- res= (rpl_global_gtid_binlog_state.count() == 0);
- mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
- return res;
+ return (rpl_global_gtid_binlog_state.count() == 0);
}
@@ -5602,10 +5606,8 @@ MYSQL_BIN_LOG::find_in_binlog_state(uint32 domain_id, uint32 server_id,
rpl_gtid *out_gtid)
{
rpl_gtid *gtid;
- mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
if ((gtid= rpl_global_gtid_binlog_state.find(domain_id, server_id)))
*out_gtid= *gtid;
- mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
return gtid != NULL;
}
@@ -5615,29 +5617,21 @@ MYSQL_BIN_LOG::lookup_domain_in_binlog_state(uint32 domain_id,
rpl_gtid *out_gtid)
{
rpl_gtid *found_gtid;
- bool res= false;
- mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
if ((found_gtid= rpl_global_gtid_binlog_state.find_most_recent(domain_id)))
{
*out_gtid= *found_gtid;
- res= true;
+ return true;
}
- mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
- return res;
+ return false;
}
int
MYSQL_BIN_LOG::bump_seq_no_counter_if_needed(uint32 domain_id, uint64 seq_no)
{
- int err;
-
- mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
- err= rpl_global_gtid_binlog_state.bump_seq_no_if_needed(domain_id, seq_no);
- mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
- return err;
+ return rpl_global_gtid_binlog_state.bump_seq_no_if_needed(domain_id, seq_no);
}
@@ -5645,13 +5639,8 @@ bool
MYSQL_BIN_LOG::check_strict_gtid_sequence(uint32 domain_id, uint32 server_id,
uint64 seq_no)
{
- bool err;
-
- mysql_mutex_lock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
- err= rpl_global_gtid_binlog_state.check_strict_sequence(domain_id, server_id,
- seq_no);
- mysql_mutex_unlock(&rpl_global_gtid_binlog_state.LOCK_binlog_state);
- return err;
+ return rpl_global_gtid_binlog_state.check_strict_sequence(domain_id,
+ server_id, seq_no);
}
@@ -8608,7 +8597,6 @@ int TC_LOG::using_heuristic_recover()
int TC_LOG_BINLOG::open(const char *opt_name)
{
- LOG_INFO log_info;
int error= 1;
DBUG_ASSERT(total_ha_2pc > 1);
@@ -8629,65 +8617,8 @@ int TC_LOG_BINLOG::open(const char *opt_name)
return 1;
}
- if ((error= find_log_pos(&log_info, NullS, 1)))
- {
- if (error != LOG_INFO_EOF)
- sql_print_error("find_log_pos() failed (error: %d)", error);
- else
- error= 0;
- goto err;
- }
-
- {
- const char *errmsg;
- IO_CACHE log;
- File file;
- Log_event *ev=0;
- Format_description_log_event fdle(BINLOG_VERSION);
- char log_name[FN_REFLEN];
-
- if (! fdle.is_valid())
- goto err;
-
- do
- {
- strmake_buf(log_name, log_info.log_file_name);
- } while (!(error= find_next_log(&log_info, 1)));
-
- if (error != LOG_INFO_EOF)
- {
- sql_print_error("find_log_pos() failed (error: %d)", error);
- goto err;
- }
-
- if ((file= open_binlog(&log, log_name, &errmsg)) < 0)
- {
- sql_print_error("%s", errmsg);
- goto err;
- }
-
- if ((ev= Log_event::read_log_event(&log, 0, &fdle,
- opt_master_verify_checksum)) &&
- ev->get_type_code() == FORMAT_DESCRIPTION_EVENT &&
- ev->flags & LOG_EVENT_BINLOG_IN_USE_F)
- {
- sql_print_information("Recovering after a crash using %s", opt_name);
- error= recover(&log_info, log_name, &log,
- (Format_description_log_event *)ev);
- state_read= true;
- }
- else
- error= read_state_from_file();
-
- delete ev;
- end_io_cache(&log);
- mysql_file_close(file, MYF(MY_WME));
-
- if (error)
- goto err;
- }
-
-err:
+ error= do_binlog_recovery(opt_name, true);
+ binlog_state_recover_done= true;
return error;
}
@@ -9064,9 +8995,9 @@ start_binlog_background_thread()
int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
IO_CACHE *first_log,
- Format_description_log_event *fdle)
+ Format_description_log_event *fdle, bool do_xa)
{
- Log_event *ev;
+ Log_event *ev= NULL;
HASH xids;
MEM_ROOT mem_root;
char binlog_checkpoint_name[FN_REFLEN];
@@ -9075,13 +9006,19 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
IO_CACHE log;
File file= -1;
const char *errmsg;
+#ifdef HAVE_REPLICATION
+ rpl_gtid last_gtid;
+ bool last_gtid_standalone= false;
+ bool last_gtid_valid= false;
+#endif
if (! fdle->is_valid() ||
- my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
- sizeof(my_xid), 0, 0, MYF(0)))
+ (do_xa && my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
+ sizeof(my_xid), 0, 0, MYF(0))))
goto err1;
- init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE, MYF(0));
+ if (do_xa)
+ init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE, MYF(0));
fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error
@@ -9101,22 +9038,23 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
0, fdle, opt_master_verify_checksum))
&& ev->is_valid())
{
- switch (ev->get_type_code())
+ enum Log_event_type typ= ev->get_type_code();
+ switch (typ)
{
case XID_EVENT:
{
- Xid_log_event *xev=(Xid_log_event *)ev;
- uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid,
- sizeof(xev->xid));
- if (!x || my_hash_insert(&xids, x))
+ if (do_xa)
{
- delete ev;
- goto err2;
+ Xid_log_event *xev=(Xid_log_event *)ev;
+ uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid,
+ sizeof(xev->xid));
+ if (!x || my_hash_insert(&xids, x))
+ goto err2;
+ break;
}
- break;
}
case BINLOG_CHECKPOINT_EVENT:
- if (first_round)
+ if (first_round && do_xa)
{
uint dir_len;
Binlog_checkpoint_log_event *cev= (Binlog_checkpoint_log_event *)ev;
@@ -9134,8 +9072,8 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
cev->binlog_file_name, FN_REFLEN - 1 - dir_len);
binlog_checkpoint_found= true;
}
- break;
}
+ break;
case GTID_LIST_EVENT:
if (first_round)
{
@@ -9147,28 +9085,49 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
}
break;
+#ifdef HAVE_REPLICATION
case GTID_EVENT:
if (first_round)
{
Gtid_log_event *gev= (Gtid_log_event *)ev;
- rpl_gtid gtid;
/* Update the binlog state with any GTID logged after Gtid_list. */
- gtid.domain_id= gev->domain_id;
- gtid.server_id= gev->server_id;
- gtid.seq_no= gev->seq_no;
- if (rpl_global_gtid_binlog_state.update(&gtid, false))
- goto err2;
+ last_gtid.domain_id= gev->domain_id;
+ last_gtid.server_id= gev->server_id;
+ last_gtid.seq_no= gev->seq_no;
+ last_gtid_standalone=
+ ((gev->flags2 & Gtid_log_event::FL_STANDALONE) ? true : false);
+ last_gtid_valid= true;
}
break;
+#endif
default:
/* Nothing. */
break;
}
+
+#ifdef HAVE_REPLICATION
+ if (last_gtid_valid &&
+ ((last_gtid_standalone && !ev->is_part_of_group(typ)) ||
+ (!last_gtid_standalone &&
+ (typ == XID_EVENT ||
+ (typ == QUERY_EVENT &&
+ (((Query_log_event *)ev)->is_commit() ||
+ ((Query_log_event *)ev)->is_rollback()))))))
+ {
+ if (rpl_global_gtid_binlog_state.update_nolock(&last_gtid, false))
+ goto err2;
+ last_gtid_valid= false;
+ }
+#endif
+
delete ev;
+ ev= NULL;
}
+ if (!do_xa)
+ break;
/*
If the last binlog checkpoint event points to an older log, we have to
scan all logs from there also, to get all possible XIDs to recover.
@@ -9221,21 +9180,28 @@ int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
}
}
- if (ha_recover(&xids))
- goto err2;
+ if (do_xa)
+ {
+ if (ha_recover(&xids))
+ goto err2;
- free_root(&mem_root, MYF(0));
- my_hash_free(&xids);
+ free_root(&mem_root, MYF(0));
+ my_hash_free(&xids);
+ }
return 0;
err2:
+ delete ev;
if (file >= 0)
{
end_io_cache(&log);
mysql_file_close(file, MYF(MY_WME));
}
- free_root(&mem_root, MYF(0));
- my_hash_free(&xids);
+ if (do_xa)
+ {
+ free_root(&mem_root, MYF(0));
+ my_hash_free(&xids);
+ }
err1:
sql_print_error("Crash recovery failed. Either correct the problem "
"(if it's, for example, out of memory error) and restart, "
@@ -9245,6 +9211,73 @@ err1:
}
+int
+MYSQL_BIN_LOG::do_binlog_recovery(const char *opt_name, bool do_xa_recovery)
+{
+ LOG_INFO log_info;
+ const char *errmsg;
+ IO_CACHE log;
+ File file;
+ Log_event *ev= 0;
+ Format_description_log_event fdle(BINLOG_VERSION);
+ char log_name[FN_REFLEN];
+ int error;
+
+ if ((error= find_log_pos(&log_info, NullS, 1)))
+ {
+ /*
+ If there are no binlog files (LOG_INFO_EOF), then we still try to read
+ the .state file to restore the binlog state. This allows to copy a server
+ to provision a new one without copying the binlog files (except the
+ master-bin.state file) and still preserve the correct binlog state.
+ */
+ if (error != LOG_INFO_EOF)
+ sql_print_error("find_log_pos() failed (error: %d)", error);
+ else
+ error= read_state_from_file();
+ return error;
+ }
+
+ if (! fdle.is_valid())
+ return 1;
+
+ do
+ {
+ strmake_buf(log_name, log_info.log_file_name);
+ } while (!(error= find_next_log(&log_info, 1)));
+
+ if (error != LOG_INFO_EOF)
+ {
+ sql_print_error("find_log_pos() failed (error: %d)", error);
+ return error;
+ }
+
+ if ((file= open_binlog(&log, log_name, &errmsg)) < 0)
+ {
+ sql_print_error("%s", errmsg);
+ return 1;
+ }
+
+ if ((ev= Log_event::read_log_event(&log, 0, &fdle,
+ opt_master_verify_checksum)) &&
+ ev->get_type_code() == FORMAT_DESCRIPTION_EVENT &&
+ ev->flags & LOG_EVENT_BINLOG_IN_USE_F)
+ {
+ sql_print_information("Recovering after a crash using %s", opt_name);
+ error= recover(&log_info, log_name, &log,
+ (Format_description_log_event *)ev, do_xa_recovery);
+ }
+ else
+ error= read_state_from_file();
+
+ delete ev;
+ end_io_cache(&log);
+ mysql_file_close(file, MYF(MY_WME));
+
+ return error;
+}
+
+
#ifdef INNODB_COMPATIBILITY_HOOKS
/**
Get the file name of the MySQL binlog.
diff --git a/sql/log.h b/sql/log.h
index ed3daa56444..73518d2594f 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -521,8 +521,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
*/
uint *sync_period_ptr;
uint sync_counter;
- /* Protect against reading the binlog state file twice. */
- bool state_read;
+ bool state_file_deleted;
+ bool binlog_state_recover_done;
inline uint get_sync_period()
{
@@ -661,7 +661,8 @@ public:
int unlog(ulong cookie, my_xid xid);
void commit_checkpoint_notify(void *cookie);
int recover(LOG_INFO *linfo, const char *last_log_name, IO_CACHE *first_log,
- Format_description_log_event *fdle);
+ Format_description_log_event *fdle, bool do_xa);
+ int do_binlog_recovery(const char *opt_name, bool do_xa_recovery);
#if !defined(MYSQL_CLIENT)
int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event,
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 6b193cdb08b..f24e85eff70 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -5909,6 +5909,8 @@ error:
thd->get_stmt_da()->set_overwrite_status(false);
close_thread_tables(thd);
/*
+ - If transaction rollback was requested due to deadlock
+ perform it and release metadata locks.
- If inside a multi-statement transaction,
defer the release of metadata locks until the current
transaction is either committed or rolled back. This prevents
@@ -5918,7 +5920,12 @@ error:
- If in autocommit mode, or outside a transactional context,
automatically release metadata locks of the current statement.
*/
- if (! thd->in_multi_stmt_transaction_mode())
+ if (thd->transaction_rollback_request)
+ {
+ trans_rollback_implicit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+ else if (! thd->in_multi_stmt_transaction_mode())
thd->mdl_context.release_transactional_locks();
else
thd->mdl_context.release_statement_locks();
@@ -9813,7 +9820,10 @@ static int rows_event_stmt_cleanup(rpl_group_info *rgi, THD * thd)
Xid_log_event will come next which will, if some transactional engines
are involved, commit the transaction and flush the pending event to the
binlog.
+ If there was a deadlock the transaction should have been rolled back
+ already. So there should be no need to rollback the transaction.
*/
+ DBUG_ASSERT(! thd->transaction_rollback_request);
error|= (error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd));
/*
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 5372cdc47b9..7b89d5bdf08 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007, 2012, Oracle and/or its affiliates.
+/* Copyright (c) 2007, 2013, Oracle and/or its affiliates.
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
@@ -1771,7 +1771,10 @@ int Old_rows_log_event::do_apply_event(rpl_group_info *rgi)
Xid_log_event will come next which will, if some transactional engines
are involved, commit the transaction and flush the pending event to the
binlog.
+ If there was a deadlock the transaction should have been rolled back
+ already. So there should be no need to rollback the transaction.
*/
+ DBUG_ASSERT(! thd->transaction_rollback_request);
if ((error= (binlog_error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd))))
rli->report(ERROR_LEVEL, error,
"Error in %s event: commit of row events failed, "
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 510ccdd528f..5dbb3407428 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -697,8 +697,6 @@ mysql_mutex_t
mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats,
LOCK_global_table_stats, LOCK_global_index_stats;
-mysql_mutex_t LOCK_rpl_gtid_state;
-
/**
The below lock protects access to two global server variables:
max_prepared_stmt_count and prepared_stmt_count. These variables
@@ -867,8 +865,6 @@ PSI_mutex_key key_LOCK_stats,
key_LOCK_global_index_stats,
key_LOCK_wakeup_ready, key_LOCK_wait_commit;
-PSI_mutex_key key_LOCK_rpl_gtid_state;
-
PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered;
PSI_mutex_key key_TABLE_SHARE_LOCK_share;
@@ -912,7 +908,6 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_global_table_stats, "LOCK_global_table_stats", PSI_FLAG_GLOBAL},
{ &key_LOCK_global_index_stats, "LOCK_global_index_stats", PSI_FLAG_GLOBAL},
{ &key_LOCK_wakeup_ready, "THD::LOCK_wakeup_ready", 0},
- { &key_LOCK_rpl_gtid_state, "LOCK_rpl_gtid_state", PSI_FLAG_GLOBAL},
{ &key_LOCK_wait_commit, "wait_for_commit::LOCK_wait_commit", 0},
{ &key_LOCK_thd_data, "THD::LOCK_thd_data", 0},
{ &key_LOCK_user_conn, "LOCK_user_conn", PSI_FLAG_GLOBAL},
@@ -1773,11 +1768,12 @@ void kill_mysql(void)
if (!kill_in_progress)
{
pthread_t tmp;
+ int error;
abort_loop=1;
- if (mysql_thread_create(0, /* Not instrumented */
- &tmp, &connection_attrib, kill_server_thread,
- (void*) 0))
- sql_print_error("Can't create thread to kill server");
+ if ((error= mysql_thread_create(0, /* Not instrumented */
+ &tmp, &connection_attrib,
+ kill_server_thread, (void*) 0)))
+ sql_print_error("Can't create thread to kill server (errno= %d).", error);
}
#endif
DBUG_VOID_RETURN;
@@ -2036,7 +2032,9 @@ void clean_up(bool print_message)
delete binlog_filter;
delete global_rpl_filter;
end_ssl();
+#ifndef EMBEDDED_LIBRARY
vio_end();
+#endif /*!EMBEDDED_LIBRARY*/
#if defined(ENABLED_DEBUG_SYNC)
/* End the debug sync facility. See debug_sync.cc. */
debug_sync_end();
@@ -2116,7 +2114,6 @@ static void clean_up_mutexes()
mysql_mutex_destroy(&LOCK_global_user_client_stats);
mysql_mutex_destroy(&LOCK_global_table_stats);
mysql_mutex_destroy(&LOCK_global_index_stats);
- mysql_mutex_destroy(&LOCK_rpl_gtid_state);
#ifdef HAVE_OPENSSL
mysql_mutex_destroy(&LOCK_des_key_file);
#ifndef HAVE_YASSL
@@ -3316,10 +3313,12 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
#endif
#ifdef USE_ONE_SIGNAL_HAND
pthread_t tmp;
- if (mysql_thread_create(0, /* Not instrumented */
- &tmp, &connection_attrib, kill_server_thread,
- (void*) &sig))
- sql_print_error("Can't create thread to kill server");
+ if ((error= mysql_thread_create(0, /* Not instrumented */
+ &tmp, &connection_attrib,
+ kill_server_thread,
+ (void*) &sig)))
+ sql_print_error("Can't create thread to kill server (errno= %d)",
+ error);
#else
kill_server((void*) sig); // MIT THREAD has a alarm thread
#endif
@@ -4352,8 +4351,6 @@ static int init_thread_environment()
&LOCK_global_table_stats, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_global_index_stats,
&LOCK_global_index_stats, MY_MUTEX_INIT_FAST);
- mysql_mutex_init(key_LOCK_rpl_gtid_state,
- &LOCK_rpl_gtid_state, MY_MUTEX_INIT_SLOW);
mysql_mutex_init(key_LOCK_prepare_ordered, &LOCK_prepare_ordered,
MY_MUTEX_INIT_SLOW);
mysql_cond_init(key_COND_prepare_ordered, &COND_prepare_ordered, NULL);
@@ -4954,9 +4951,12 @@ static void create_shutdown_thread()
#ifdef __WIN__
hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name);
pthread_t hThread;
- if (mysql_thread_create(key_thread_handle_shutdown,
- &hThread, &connection_attrib, handle_shutdown, 0))
- sql_print_warning("Can't create thread to handle shutdown requests");
+ int error;
+ if ((error= mysql_thread_create(key_thread_handle_shutdown,
+ &hThread, &connection_attrib,
+ handle_shutdown, 0)))
+ sql_print_warning("Can't create thread to handle shutdown requests"
+ " (errno= %d)", error);
// On "Stop Service" we have to do regular shutdown
Service.SetShutdownEvent(hEventShutdown);
@@ -4970,6 +4970,7 @@ static void create_shutdown_thread()
static void handle_connections_methods()
{
pthread_t hThread;
+ int error;
DBUG_ENTER("handle_connections_methods");
if (hPipe == INVALID_HANDLE_VALUE &&
(!have_tcpip || opt_disable_networking) &&
@@ -4985,22 +4986,24 @@ static void handle_connections_methods()
if (hPipe != INVALID_HANDLE_VALUE)
{
handler_count++;
- if (mysql_thread_create(key_thread_handle_con_namedpipes,
- &hThread, &connection_attrib,
- handle_connections_namedpipes, 0))
+ if ((error= mysql_thread_create(key_thread_handle_con_namedpipes,
+ &hThread, &connection_attrib,
+ handle_connections_namedpipes, 0)))
{
- sql_print_warning("Can't create thread to handle named pipes");
+ sql_print_warning("Can't create thread to handle named pipes"
+ " (errno= %d)", error);
handler_count--;
}
}
if (have_tcpip && !opt_disable_networking)
{
handler_count++;
- if (mysql_thread_create(key_thread_handle_con_sockets,
- &hThread, &connection_attrib,
- handle_connections_sockets_thread, 0))
+ if ((error= mysql_thread_create(key_thread_handle_con_sockets,
+ &hThread, &connection_attrib,
+ handle_connections_sockets_thread, 0)))
{
- sql_print_warning("Can't create thread to handle TCP/IP");
+ sql_print_warning("Can't create thread to handle TCP/IP",
+ " (errno= %d)", error);
handler_count--;
}
}
@@ -5008,11 +5011,12 @@ static void handle_connections_methods()
if (opt_enable_shared_memory)
{
handler_count++;
- if (mysql_thread_create(key_thread_handle_con_sharedmem,
- &hThread, &connection_attrib,
- handle_connections_shared_memory, 0))
+ if ((error= mysql_thread_create(key_thread_handle_con_sharedmem,
+ &hThread, &connection_attrib,
+ handle_connections_shared_memory, 0)))
{
- sql_print_warning("Can't create thread to handle shared memory");
+ sql_print_warning("Can't create thread to handle shared memory",
+ " (errno= %d)", error);
handler_count--;
}
}
@@ -5038,6 +5042,42 @@ void decrement_handler_count()
#ifndef EMBEDDED_LIBRARY
+
+LEX_STRING sql_statement_names[(uint) SQLCOM_END + 1];
+
+static void init_sql_statement_names()
+{
+ char *first_com= (char*) offsetof(STATUS_VAR, com_stat[0]);
+ char *last_com= (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_END]);
+ int record_size= (char*) offsetof(STATUS_VAR, com_stat[1])
+ - (char*) offsetof(STATUS_VAR, com_stat[0]);
+ char *ptr;
+ uint i;
+ uint com_index;
+
+ for (i= 0; i < ((uint) SQLCOM_END + 1); i++)
+ sql_statement_names[i]= empty_lex_str;
+
+ SHOW_VAR *var= &com_status_vars[0];
+ while (var->name != NULL)
+ {
+ ptr= var->value;
+ if ((first_com <= ptr) && (ptr <= last_com))
+ {
+ com_index= ((int)(ptr - first_com))/record_size;
+ DBUG_ASSERT(com_index < (uint) SQLCOM_END);
+ sql_statement_names[com_index].str= const_cast<char *>(var->name);
+ sql_statement_names[com_index].length= strlen(var->name);
+ }
+ var++;
+ }
+
+ DBUG_ASSERT(strcmp(sql_statement_names[(uint) SQLCOM_SELECT].str, "select") == 0);
+ DBUG_ASSERT(strcmp(sql_statement_names[(uint) SQLCOM_SIGNAL].str, "signal") == 0);
+
+ sql_statement_names[(uint) SQLCOM_END].str= const_cast<char*>("error");
+}
+
#ifndef DBUG_OFF
/*
Debugging helper function to keep the locale database
@@ -5116,6 +5156,7 @@ int mysqld_main(int argc, char **argv)
/* Must be initialized early for comparison of options name */
system_charset_info= &my_charset_utf8_general_ci;
+ init_sql_statement_names();
sys_var_init();
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
@@ -5715,11 +5756,14 @@ static void bootstrap(MYSQL_FILE *file)
bootstrap_file=file;
#ifndef EMBEDDED_LIBRARY // TODO: Enable this
- if (mysql_thread_create(key_thread_bootstrap,
- &thd->real_id, &connection_attrib, handle_bootstrap,
- (void*) thd))
+ int error;
+ if ((error= mysql_thread_create(key_thread_bootstrap,
+ &thd->real_id, &connection_attrib,
+ handle_bootstrap,
+ (void*) thd)))
{
- sql_print_warning("Can't create thread to handle bootstrap");
+ sql_print_warning("Can't create thread to handle bootstrap (errno= %d)",
+ error);
bootstrap_error=-1;
DBUG_VOID_RETURN;
}
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 57ecfbb5553..1b718cb8f05 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -217,7 +217,6 @@ extern LEX_STRING opt_init_connect, opt_init_slave;
extern int bootstrap_error;
extern I_List<THD> threads;
extern char err_shared_dir[];
-extern TYPELIB thread_handling_typelib;
extern ulong connection_errors_select;
extern ulong connection_errors_accept;
extern ulong connection_errors_tcpwrap;
@@ -268,8 +267,6 @@ extern PSI_mutex_key key_TABLE_SHARE_LOCK_share, key_LOCK_stats,
key_LOCK_global_user_client_stats, key_LOCK_global_table_stats,
key_LOCK_global_index_stats, key_LOCK_wakeup_ready, key_LOCK_wait_commit;
-extern PSI_mutex_key key_LOCK_rpl_gtid_state;
-
extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger,
key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave,
key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock;
@@ -496,7 +493,6 @@ extern mysql_mutex_t
LOCK_slave_list, LOCK_active_mi, LOCK_manager,
LOCK_global_system_variables, LOCK_user_conn,
LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count;
-extern mysql_mutex_t LOCK_rpl_gtid_state;
extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_thread_count;
#ifdef HAVE_OPENSSL
extern mysql_mutex_t LOCK_des_key_file;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 384c99cff54..6982db898fb 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3410,6 +3410,9 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item *cond)
if (table_records == 0)
DBUG_RETURN(FALSE);
+
+ if (table->pos_in_table_list->schema_table)
+ DBUG_RETURN(FALSE);
if (thd->variables.optimizer_use_condition_selectivity > 2 &&
!bitmap_is_clear_all(used_fields))
@@ -5360,8 +5363,10 @@ TABLE_READ_PLAN *merge_same_index_scans(PARAM *param, SEL_IMERGE *imerge,
bzero((*changed_tree)->keys,
sizeof((*changed_tree)->keys[0])*param->keys);
(*changed_tree)->keys_map.clear_all();
- key->incr_refs();
- (*tree)->keys[key_idx]->incr_refs();
+ if (key)
+ key->incr_refs();
+ if ((*tree)->keys[key_idx])
+ (*tree)->keys[key_idx]->incr_refs();
if (((*changed_tree)->keys[key_idx]=
key_or(param, key, (*tree)->keys[key_idx])))
(*changed_tree)->keys_map.set_bit(key_idx);
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index c156c1642e7..a9bff4b37bf 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -1311,7 +1311,6 @@ static bool replace_where_subcondition(JOIN *join, Item **expr,
}
else if (item->type() == Item::COND_ITEM)
{
- DBUG_ASSERT(!do_fix_fields || !(*expr)->fixed);
replace_where_subcondition(join, li.ref(),
old_cond, new_cond,
do_fix_fields);
@@ -1929,11 +1928,25 @@ int pull_out_semijoin_tables(JOIN *join)
}
}
-
table_map pulled_tables= 0;
+ table_map dep_tables= 0;
if (have_join_nest_children)
goto skip;
+ /*
+ Calculate set of tables within this semi-join nest that have
+ other dependent tables
+ */
+ child_li.rewind();
+ while ((tbl= child_li++))
+ {
+ TABLE *const table= tbl->table;
+ if (table &&
+ (table->reginfo.join_tab->dependent &
+ sj_nest->nested_join->used_tables))
+ dep_tables|= table->reginfo.join_tab->dependent;
+ }
+
/* Action #1: Mark the constant tables to be pulled out */
child_li.rewind();
while ((tbl= child_li++))
@@ -1984,7 +1997,8 @@ int pull_out_semijoin_tables(JOIN *join)
child_li.rewind();
while ((tbl= child_li++))
{
- if (tbl->table && !(pulled_tables & tbl->table->map))
+ if (tbl->table && !(pulled_tables & tbl->table->map) &&
+ !(dep_tables & tbl->table->map))
{
if (find_eq_ref_candidate(tbl->table,
sj_nest->nested_join->used_tables &
diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc
index e50a9b0b42d..46bed0e60e7 100644
--- a/sql/opt_table_elimination.cc
+++ b/sql/opt_table_elimination.cc
@@ -609,6 +609,21 @@ void eliminate_tables(JOIN *join)
/* Find the tables that are referred to from WHERE/HAVING */
used_tables= (join->conds? join->conds->used_tables() : 0) |
(join->having? join->having->used_tables() : 0);
+
+ /*
+ For "INSERT ... SELECT ... ON DUPLICATE KEY UPDATE column = val"
+ we should also take into account tables mentioned in "val".
+ */
+ if (join->thd->lex->sql_command == SQLCOM_INSERT_SELECT &&
+ join->select_lex == &thd->lex->select_lex)
+ {
+ List_iterator<Item> val_it(thd->lex->value_list);
+ while ((item= val_it++))
+ {
+ DBUG_ASSERT(item->fixed);
+ used_tables |= item->used_tables();
+ }
+ }
/* Add tables referred to from the select list */
List_iterator<Item> it(join->fields_list);
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index c5f1d68dda1..44407bd737f 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -2793,11 +2793,10 @@ bool partition_info::fix_parser_data(THD *thd)
{
part_elem= it++;
List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
- j= 0;
num_elements= part_elem->list_val_list.elements;
DBUG_ASSERT(part_type == RANGE_PARTITION ?
num_elements == 1U : TRUE);
- do
+ for (j= 0; j < num_elements; j++)
{
part_elem_value *val= list_val_it++;
if (column_list)
@@ -2832,7 +2831,7 @@ bool partition_info::fix_parser_data(THD *thd)
list_val_it.remove();
}
}
- } while (++j < num_elements);
+ }
} while (++i < num_parts);
DBUG_RETURN(FALSE);
}
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index 8429f1c7f58..3f79a0cb528 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -203,18 +203,15 @@ rpl_slave_state::truncate_state_table(THD *thd)
{
TABLE_LIST tlist;
int err= 0;
- TABLE *table;
+ tmp_disable_binlog(thd);
tlist.init_one_table(STRING_WITH_LEN("mysql"),
rpl_gtid_slave_state_table_name.str,
rpl_gtid_slave_state_table_name.length,
NULL, TL_WRITE);
if (!(err= open_and_lock_tables(thd, &tlist, FALSE, 0)))
{
- table= tlist.table;
- table->no_replicate= 1;
- table->s->is_gtid_slave_pos= TRUE; // TEMPORARY CODE
- err= table->file->ha_truncate();
+ err= tlist.table->file->ha_truncate();
if (err)
{
@@ -231,6 +228,7 @@ rpl_slave_state::truncate_state_table(THD *thd)
thd->mdl_context.release_transactional_locks();
}
+ reenable_binlog(thd);
return err;
}
@@ -350,14 +348,14 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
if ((err= gtid_check_rpl_slave_state_table(table)))
goto end;
- table->no_replicate= 1;
- table->s->is_gtid_slave_pos= TRUE; // TEMPORARY CODE
if (!in_transaction)
{
DBUG_PRINT("info", ("resetting OPTION_BEGIN"));
thd->variables.option_bits&=
- ~(ulonglong)(OPTION_NOT_AUTOCOMMIT|OPTION_BEGIN);
+ ~(ulonglong)(OPTION_NOT_AUTOCOMMIT|OPTION_BEGIN|OPTION_BIN_LOG);
}
+ else
+ thd->variables.option_bits&= ~(ulonglong)OPTION_BIN_LOG;
bitmap_set_all(table->write_set);
@@ -840,7 +838,7 @@ rpl_binlog_state::rpl_binlog_state()
void
-rpl_binlog_state::reset()
+rpl_binlog_state::reset_nolock()
{
uint32 i;
@@ -849,12 +847,22 @@ rpl_binlog_state::reset()
my_hash_reset(&hash);
}
+
+void
+rpl_binlog_state::reset()
+{
+ mysql_mutex_lock(&LOCK_binlog_state);
+ reset_nolock();
+ mysql_mutex_unlock(&LOCK_binlog_state);
+}
+
+
void rpl_binlog_state::free()
{
if (initialized)
{
initialized= 0;
- reset();
+ reset_nolock();
my_hash_free(&hash);
mysql_mutex_destroy(&LOCK_binlog_state);
}
@@ -865,14 +873,20 @@ bool
rpl_binlog_state::load(struct rpl_gtid *list, uint32 count)
{
uint32 i;
+ bool res= false;
- reset();
+ mysql_mutex_lock(&LOCK_binlog_state);
+ reset_nolock();
for (i= 0; i < count; ++i)
{
- if (update(&(list[i]), false))
- return true;
+ if (update_nolock(&(list[i]), false))
+ {
+ res= true;
+ break;
+ }
}
- return false;
+ mysql_mutex_unlock(&LOCK_binlog_state);
+ return res;
}
@@ -891,7 +905,7 @@ rpl_binlog_state::~rpl_binlog_state()
Returns 0 for ok, 1 for error.
*/
int
-rpl_binlog_state::update(const struct rpl_gtid *gtid, bool strict)
+rpl_binlog_state::update_nolock(const struct rpl_gtid *gtid, bool strict)
{
element *elem;
@@ -910,7 +924,7 @@ rpl_binlog_state::update(const struct rpl_gtid *gtid, bool strict)
if (!elem->update_element(gtid))
return 0;
}
- else if (!alloc_element(gtid))
+ else if (!alloc_element_nolock(gtid))
return 0;
my_error(ER_OUT_OF_RESOURCES, MYF(0));
@@ -918,6 +932,17 @@ rpl_binlog_state::update(const struct rpl_gtid *gtid, bool strict)
}
+int
+rpl_binlog_state::update(const struct rpl_gtid *gtid, bool strict)
+{
+ int res;
+ mysql_mutex_lock(&LOCK_binlog_state);
+ res= update_nolock(gtid, strict);
+ mysql_mutex_unlock(&LOCK_binlog_state);
+ return res;
+}
+
+
/*
Fill in a new GTID, allocating next sequence number, and update state
accordingly.
@@ -927,25 +952,30 @@ rpl_binlog_state::update_with_next_gtid(uint32 domain_id, uint32 server_id,
rpl_gtid *gtid)
{
element *elem;
+ int res= 0;
gtid->domain_id= domain_id;
gtid->server_id= server_id;
+ mysql_mutex_lock(&LOCK_binlog_state);
if ((elem= (element *)my_hash_search(&hash, (const uchar *)(&domain_id), 0)))
{
gtid->seq_no= ++elem->seq_no_counter;
if (!elem->update_element(gtid))
- return 0;
+ goto end;
}
else
{
gtid->seq_no= 1;
- if (!alloc_element(gtid))
- return 0;
+ if (!alloc_element_nolock(gtid))
+ goto end;
}
my_error(ER_OUT_OF_RESOURCES, MYF(0));
- return 1;
+ res= 1;
+end:
+ mysql_mutex_unlock(&LOCK_binlog_state);
+ return res;
}
@@ -991,7 +1021,7 @@ rpl_binlog_state::element::update_element(const rpl_gtid *gtid)
int
-rpl_binlog_state::alloc_element(const rpl_gtid *gtid)
+rpl_binlog_state::alloc_element_nolock(const rpl_gtid *gtid)
{
element *elem;
rpl_gtid *lookup_gtid;
@@ -1035,7 +1065,9 @@ rpl_binlog_state::check_strict_sequence(uint32 domain_id, uint32 server_id,
uint64 seq_no)
{
element *elem;
+ bool res= 0;
+ mysql_mutex_lock(&LOCK_binlog_state);
if ((elem= (element *)my_hash_search(&hash,
(const uchar *)(&domain_id), 0)) &&
elem->last_gtid && elem->last_gtid->seq_no >= seq_no)
@@ -1043,9 +1075,10 @@ rpl_binlog_state::check_strict_sequence(uint32 domain_id, uint32 server_id,
my_error(ER_GTID_STRICT_OUT_OF_ORDER, MYF(0), domain_id, server_id, seq_no,
elem->last_gtid->domain_id, elem->last_gtid->server_id,
elem->last_gtid->seq_no);
- return 1;
+ res= 1;
}
- return 0;
+ mysql_mutex_unlock(&LOCK_binlog_state);
+ return res;
}
@@ -1060,17 +1093,23 @@ int
rpl_binlog_state::bump_seq_no_if_needed(uint32 domain_id, uint64 seq_no)
{
element *elem;
+ int res;
+ mysql_mutex_lock(&LOCK_binlog_state);
if ((elem= (element *)my_hash_search(&hash, (const uchar *)(&domain_id), 0)))
{
if (elem->seq_no_counter < seq_no)
elem->seq_no_counter= seq_no;
- return 0;
+ res= 0;
+ goto end;
}
/* We need to allocate a new, empty element to remember the next seq_no. */
if (!(elem= (element *)my_malloc(sizeof(*elem), MYF(MY_WME))))
- return 1;
+ {
+ res= 1;
+ goto end;
+ }
elem->domain_id= domain_id;
my_hash_init(&elem->hash, &my_charset_bin, 32,
@@ -1079,11 +1118,18 @@ rpl_binlog_state::bump_seq_no_if_needed(uint32 domain_id, uint64 seq_no)
elem->last_gtid= NULL;
elem->seq_no_counter= seq_no;
if (0 == my_hash_insert(&hash, (const uchar *)elem))
- return 0;
+ {
+ res= 0;
+ goto end;
+ }
my_hash_free(&elem->hash);
my_free(elem);
- return 1;
+ res= 1;
+
+end:
+ mysql_mutex_unlock(&LOCK_binlog_state);
+ return res;
}
@@ -1099,7 +1145,9 @@ rpl_binlog_state::write_to_iocache(IO_CACHE *dest)
{
ulong i, j;
char buf[21];
+ int res= 0;
+ mysql_mutex_lock(&LOCK_binlog_state);
for (i= 0; i < hash.records; ++i)
{
size_t res;
@@ -1124,11 +1172,16 @@ rpl_binlog_state::write_to_iocache(IO_CACHE *dest)
longlong10_to_str(gtid->seq_no, buf, 10);
res= my_b_printf(dest, "%u-%u-%s\n", gtid->domain_id, gtid->server_id, buf);
if (res == (size_t) -1)
- return 1;
+ {
+ res= 1;
+ goto end;
+ }
}
}
- return 0;
+end:
+ mysql_mutex_unlock(&LOCK_binlog_state);
+ return res;
}
@@ -1139,26 +1192,31 @@ rpl_binlog_state::read_from_iocache(IO_CACHE *src)
char buf[10+1+10+1+20+1+1];
char *p, *end;
rpl_gtid gtid;
+ int res= 0;
- reset();
+ mysql_mutex_lock(&LOCK_binlog_state);
+ reset_nolock();
for (;;)
{
- size_t res= my_b_gets(src, buf, sizeof(buf));
- if (!res)
+ size_t len= my_b_gets(src, buf, sizeof(buf));
+ if (!len)
break;
p= buf;
- end= buf + res;
- if (gtid_parser_helper(&p, end, &gtid))
- return 1;
- if (update(&gtid, false))
- return 1;
+ end= buf + len;
+ if (gtid_parser_helper(&p, end, &gtid) ||
+ update_nolock(&gtid, false))
+ {
+ res= 1;
+ break;
+ }
}
- return 0;
+ mysql_mutex_unlock(&LOCK_binlog_state);
+ return res;
}
rpl_gtid *
-rpl_binlog_state::find(uint32 domain_id, uint32 server_id)
+rpl_binlog_state::find_nolock(uint32 domain_id, uint32 server_id)
{
element *elem;
if (!(elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id, 0)))
@@ -1167,14 +1225,28 @@ rpl_binlog_state::find(uint32 domain_id, uint32 server_id)
}
rpl_gtid *
+rpl_binlog_state::find(uint32 domain_id, uint32 server_id)
+{
+ rpl_gtid *p;
+ mysql_mutex_lock(&LOCK_binlog_state);
+ p= find_nolock(domain_id, server_id);
+ mysql_mutex_unlock(&LOCK_binlog_state);
+ return p;
+}
+
+rpl_gtid *
rpl_binlog_state::find_most_recent(uint32 domain_id)
{
element *elem;
+ rpl_gtid *gtid= NULL;
+ mysql_mutex_lock(&LOCK_binlog_state);
elem= (element *)my_hash_search(&hash, (const uchar *)&domain_id, 0);
if (elem && elem->last_gtid)
- return elem->last_gtid;
- return NULL;
+ gtid= elem->last_gtid;
+ mysql_mutex_unlock(&LOCK_binlog_state);
+
+ return gtid;
}
@@ -1184,8 +1256,10 @@ rpl_binlog_state::count()
uint32 c= 0;
uint32 i;
+ mysql_mutex_lock(&LOCK_binlog_state);
for (i= 0; i < hash.records; ++i)
c+= ((element *)my_hash_element(&hash, i))->hash.records;
+ mysql_mutex_unlock(&LOCK_binlog_state);
return c;
}
@@ -1195,7 +1269,9 @@ int
rpl_binlog_state::get_gtid_list(rpl_gtid *gtid_list, uint32 list_size)
{
uint32 i, j, pos;
+ int res= 0;
+ mysql_mutex_lock(&LOCK_binlog_state);
pos= 0;
for (i= 0; i < hash.records; ++i)
{
@@ -1218,12 +1294,17 @@ rpl_binlog_state::get_gtid_list(rpl_gtid *gtid_list, uint32 list_size)
gtid= e->last_gtid;
if (pos >= list_size)
- return 1;
+ {
+ res= 1;
+ goto end;
+ }
memcpy(&gtid_list[pos++], gtid, sizeof(*gtid));
}
}
- return 0;
+end:
+ mysql_mutex_unlock(&LOCK_binlog_state);
+ return res;
}
@@ -1242,12 +1323,17 @@ rpl_binlog_state::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size)
{
uint32 i;
uint32 alloc_size, out_size;
+ int res= 0;
+ out_size= 0;
+ mysql_mutex_lock(&LOCK_binlog_state);
alloc_size= hash.records;
if (!(*list= (rpl_gtid *)my_malloc(alloc_size * sizeof(rpl_gtid),
MYF(MY_WME))))
- return 1;
- out_size= 0;
+ {
+ res= 1;
+ goto end;
+ }
for (i= 0; i < alloc_size; ++i)
{
element *e= (element *)my_hash_element(&hash, i);
@@ -1256,8 +1342,10 @@ rpl_binlog_state::get_most_recent_gtid_list(rpl_gtid **list, uint32 *size)
memcpy(&((*list)[out_size++]), e->last_gtid, sizeof(rpl_gtid));
}
+end:
+ mysql_mutex_unlock(&LOCK_binlog_state);
*size= out_size;
- return 0;
+ return res;
}
@@ -1267,6 +1355,7 @@ rpl_binlog_state::append_pos(String *str)
uint32 i;
bool first= true;
+ mysql_mutex_lock(&LOCK_binlog_state);
for (i= 0; i < hash.records; ++i)
{
element *e= (element *)my_hash_element(&hash, i);
@@ -1274,6 +1363,7 @@ rpl_binlog_state::append_pos(String *str)
rpl_slave_state_tostring_helper(str, e->last_gtid, &first))
return true;
}
+ mysql_mutex_unlock(&LOCK_binlog_state);
return false;
}
@@ -1284,7 +1374,9 @@ rpl_binlog_state::append_state(String *str)
{
uint32 i, j;
bool first= true;
+ bool res= false;
+ mysql_mutex_lock(&LOCK_binlog_state);
for (i= 0; i < hash.records; ++i)
{
element *e= (element *)my_hash_element(&hash, i);
@@ -1306,11 +1398,16 @@ rpl_binlog_state::append_state(String *str)
gtid= e->last_gtid;
if (rpl_slave_state_tostring_helper(str, gtid, &first))
- return true;
+ {
+ res= true;
+ goto end;
+ }
}
}
- return false;
+end:
+ mysql_mutex_unlock(&LOCK_binlog_state);
+ return res;
}
diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h
index a503184cee6..b0bc54900e7 100644
--- a/sql/rpl_gtid.h
+++ b/sql/rpl_gtid.h
@@ -146,13 +146,15 @@ struct rpl_binlog_state
rpl_binlog_state();
~rpl_binlog_state();
+ void reset_nolock();
void reset();
void free();
bool load(struct rpl_gtid *list, uint32 count);
+ int update_nolock(const struct rpl_gtid *gtid, bool strict);
int update(const struct rpl_gtid *gtid, bool strict);
int update_with_next_gtid(uint32 domain_id, uint32 server_id,
rpl_gtid *gtid);
- int alloc_element(const rpl_gtid *gtid);
+ int alloc_element_nolock(const rpl_gtid *gtid);
bool check_strict_sequence(uint32 domain_id, uint32 server_id, uint64 seq_no);
int bump_seq_no_if_needed(uint32 domain_id, uint64 seq_no);
int write_to_iocache(IO_CACHE *dest);
@@ -162,6 +164,7 @@ struct rpl_binlog_state
int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size);
bool append_pos(String *str);
bool append_state(String *str);
+ rpl_gtid *find_nolock(uint32 domain_id, uint32 server_id);
rpl_gtid *find(uint32 domain_id, uint32 server_id);
rpl_gtid *find_most_recent(uint32 domain_id);
};
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 5e711bb07e0..9036f810020 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2006, 2012, Oracle and/or its affiliates.
- Copyright (c) 2010, 2012, Monty Program Ab.
+/* Copyright (c) 2006, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2013, Monty Program Ab
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
@@ -1676,6 +1676,8 @@ void rpl_group_info::slave_close_thread_tables(THD *thd)
close_thread_tables(thd);
/*
+ - If transaction rollback was requested due to deadlock
+ perform it and release metadata locks.
- If inside a multi-statement transaction,
defer the release of metadata locks until the current
transaction is either committed or rolled back. This prevents
@@ -1685,7 +1687,12 @@ void rpl_group_info::slave_close_thread_tables(THD *thd)
- If in autocommit mode, or outside a transactional context,
automatically release metadata locks of the current statement.
*/
- if (! thd->in_multi_stmt_transaction_mode())
+ if (thd->transaction_rollback_request)
+ {
+ trans_rollback_implicit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+ else if (! thd->in_multi_stmt_transaction_mode())
thd->mdl_context.release_transactional_locks();
else
thd->mdl_context.release_statement_locks();
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index 1f67dd6ee8f..e8bc042e565 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -1,6 +1,5 @@
-/*
- Copyright (c) 2006, 2010, Oracle and/or its affiliates.
- Copyright (c) 2011, 2013, Monty Program Ab.
+/* Copyright (c) 2006, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2013, Monty Program Ab
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
@@ -946,6 +945,7 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *
DBUG_ENTER("table_def::create_conversion_table");
List<Create_field> field_list;
+ TABLE *conv_table= NULL;
/*
At slave, columns may differ. So we should create
MY_MIN(columns@master, columns@slave) columns in the
@@ -987,10 +987,15 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *
break;
case MYSQL_TYPE_DECIMAL:
- precision= field_metadata(col);
- decimals= static_cast<Field_num*>(target_table->field[col])->dec;
- max_length= field_metadata(col);
- break;
+ sql_print_error("In RBR mode, Slave received incompatible DECIMAL field "
+ "(old-style decimal field) from Master while creating "
+ "conversion table. Please consider changing datatype on "
+ "Master to new style decimal by executing ALTER command for"
+ " column Name: %s.%s.%s.",
+ target_table->s->db.str,
+ target_table->s->table_name.str,
+ target_table->field[col]->field_name);
+ goto err;
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
@@ -1018,7 +1023,9 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *
field_def->interval= interval;
}
- TABLE *conv_table= create_virtual_tmp_table(thd, field_list);
+ conv_table= create_virtual_tmp_table(thd, field_list);
+
+err:
if (conv_table == NULL)
rli->report(ERROR_LEVEL, ER_SLAVE_CANT_CREATE_CONVERSION,
ER(ER_SLAVE_CANT_CREATE_CONVERSION),
diff --git a/sql/slave.cc b/sql/slave.cc
index 0912d77e070..835b0d9b15a 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -792,6 +792,7 @@ int start_slave_thread(
{
pthread_t th;
ulong start_id;
+ int error;
DBUG_ENTER("start_slave_thread");
DBUG_ASSERT(mi->inited);
@@ -818,9 +819,10 @@ int start_slave_thread(
}
start_id= *slave_run_id;
DBUG_PRINT("info",("Creating new slave thread"));
- if (mysql_thread_create(thread_key,
- &th, &connection_attrib, h_func, (void*)mi))
+ if ((error = mysql_thread_create(thread_key,
+ &th, &connection_attrib, h_func, (void*)mi)))
{
+ sql_print_error("Can't create slave thread (errno= %d).", error);
if (start_lock)
mysql_mutex_unlock(start_lock);
DBUG_RETURN(ER_SLAVE_THREAD);
@@ -2497,6 +2499,7 @@ static bool send_show_master_info_header(THD *thd, bool full,
sizeof(mi->ssl_crlpath)));
field_list.push_back(new Item_empty_string("Using_Gtid",
sizeof("Current_Pos")-1));
+ field_list.push_back(new Item_empty_string("Gtid_IO_Pos", 30));
if (full)
{
field_list.push_back(new Item_return_int("Retried_transactions",
@@ -2690,6 +2693,12 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
// Master_Ssl_Crlpath
protocol->store(mi->ssl_capath, &my_charset_bin);
protocol->store(mi->using_gtid_astext(mi->using_gtid), &my_charset_bin);
+ {
+ char buff[30];
+ String tmp(buff, sizeof(buff), system_charset_info);
+ mi->gtid_current_pos.to_string(&tmp);
+ protocol->store(tmp.ptr(), tmp.length(), &my_charset_bin);
+ }
if (full)
{
protocol->store((uint32) mi->rli.retried_trans);
@@ -3464,6 +3473,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli,
if (exec_res && (temp_err= has_temporary_error(thd)))
{
const char *errmsg;
+ rli->clear_error();
/*
We were in a transaction which has been rolled back because of a
temporary error;
@@ -3976,7 +3986,7 @@ Stopping slave I/O thread due to out-of-memory error from master");
goto err;
}
- if (mi->using_gtid != Master_info::USE_GTID_NO &&
+ if (mi->using_gtid == Master_info::USE_GTID_NO &&
flush_master_info(mi, TRUE, TRUE))
{
sql_print_error("Failed to flush master info file");
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 4bf6c13a7d8..84e2c3069c3 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1,5 +1,6 @@
/*
- Copyright (c) 2002, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2002, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2013, Monty Program Ab
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
@@ -2102,10 +2103,18 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
close_thread_tables(thd);
thd_proc_info(thd, 0);
- if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
- thd->mdl_context.release_transactional_locks();
- else if (! thd->in_sub_stmt)
- thd->mdl_context.release_statement_locks();
+ if (! thd->in_sub_stmt)
+ {
+ if (thd->transaction_rollback_request)
+ {
+ trans_rollback_implicit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+ else if (! thd->in_multi_stmt_transaction_mode())
+ thd->mdl_context.release_transactional_locks();
+ else
+ thd->mdl_context.release_statement_locks();
+ }
thd->rollback_item_tree_changes();
@@ -2964,10 +2973,18 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
close_thread_tables(thd);
thd_proc_info(thd, 0);
- if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
- thd->mdl_context.release_transactional_locks();
- else if (! thd->in_sub_stmt)
- thd->mdl_context.release_statement_locks();
+ if (! thd->in_sub_stmt)
+ {
+ if (thd->transaction_rollback_request)
+ {
+ trans_rollback_implicit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+ else if (! thd->in_multi_stmt_transaction_mode())
+ thd->mdl_context.release_transactional_locks();
+ else
+ thd->mdl_context.release_statement_locks();
+ }
}
//TODO: why is this here if log_slow_query is in sp_instr_stmt_execute?
delete_explain_query(m_lex);
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index a63457159db..a297e18ab47 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -993,8 +993,20 @@ send_result_message:
}
}
/* Error path, a admin command failed. */
- trans_commit_stmt(thd);
- trans_commit_implicit(thd);
+ if (thd->transaction_rollback_request)
+ {
+ /*
+ Unlikely, but transaction rollback was requested by one of storage
+ engines (e.g. due to deadlock). Perform it.
+ */
+ if (trans_rollback_stmt(thd) || trans_rollback_implicit(thd))
+ goto err;
+ }
+ else
+ {
+ if (trans_commit_stmt(thd) || trans_commit_implicit(thd))
+ goto err;
+ }
close_thread_tables(thd);
thd->mdl_context.release_transactional_locks();
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index a949cf98066..e3ce2adf862 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 2010, 2011 Monty Program Ab
+/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2013 Monty Program Ab
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
@@ -3202,7 +3202,8 @@ end_free:
/** Open_table_context */
Open_table_context::Open_table_context(THD *thd, uint flags)
- :m_failed_table(NULL),
+ :m_thd(thd),
+ m_failed_table(NULL),
m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()),
m_timeout(flags & MYSQL_LOCK_IGNORE_TIMEOUT ?
LONG_TIMEOUT : thd->variables.lock_wait_timeout),
@@ -3279,6 +3280,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);
return TRUE;
}
/*
@@ -3288,7 +3290,7 @@ request_backoff_action(enum_open_table_action action_arg,
if (table)
{
DBUG_ASSERT(action_arg == OT_DISCOVER || action_arg == OT_REPAIR);
- m_failed_table= (TABLE_LIST*) current_thd->alloc(sizeof(TABLE_LIST));
+ m_failed_table= (TABLE_LIST*) m_thd->alloc(sizeof(TABLE_LIST));
if (m_failed_table == NULL)
return TRUE;
m_failed_table->init_one_table(table->db, table->db_length,
@@ -3306,8 +3308,6 @@ request_backoff_action(enum_open_table_action action_arg,
/**
Recover from failed attempt of open table by performing requested action.
- @param thd Thread context
-
@pre This function should be called only with "action" != OT_NO_ACTION
and after having called @sa close_tables_for_reopen().
@@ -3316,7 +3316,7 @@ request_backoff_action(enum_open_table_action action_arg,
*/
bool
-Open_table_context::recover_from_failed_open(THD *thd)
+Open_table_context::recover_from_failed_open()
{
bool result= FALSE;
/* Execute the action. */
@@ -3328,46 +3328,46 @@ Open_table_context::recover_from_failed_open(THD *thd)
break;
case OT_DISCOVER:
{
- if ((result= lock_table_names(thd, m_failed_table, NULL,
+ if ((result= lock_table_names(m_thd, m_failed_table, NULL,
get_timeout(), 0)))
break;
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
+ tdc_remove_table(m_thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
m_failed_table->table_name, FALSE);
- thd->get_stmt_da()->clear_warning_info(thd->query_id);
- thd->clear_error(); // Clear error message
+ m_thd->get_stmt_da()->clear_warning_info(m_thd->query_id);
+ m_thd->clear_error(); // Clear error message
No_such_table_error_handler no_such_table_handler;
bool open_if_exists= m_failed_table->open_strategy == TABLE_LIST::OPEN_IF_EXISTS;
if (open_if_exists)
- thd->push_internal_handler(&no_such_table_handler);
+ m_thd->push_internal_handler(&no_such_table_handler);
- result= !tdc_acquire_share(thd, m_failed_table->db,
+ result= !tdc_acquire_share(m_thd, m_failed_table->db,
m_failed_table->table_name,
GTS_TABLE | GTS_FORCE_DISCOVERY | GTS_NOLOCK);
if (open_if_exists)
{
- thd->pop_internal_handler();
+ m_thd->pop_internal_handler();
if (result && no_such_table_handler.safely_trapped_errors())
result= FALSE;
}
- thd->mdl_context.release_transactional_locks();
+ m_thd->mdl_context.release_transactional_locks();
break;
}
case OT_REPAIR:
{
- if ((result= lock_table_names(thd, m_failed_table, NULL,
+ if ((result= lock_table_names(m_thd, m_failed_table, NULL,
get_timeout(), 0)))
break;
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
+ tdc_remove_table(m_thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
m_failed_table->table_name, FALSE);
- result= auto_repair_table(thd, m_failed_table);
- thd->mdl_context.release_transactional_locks();
+ result= auto_repair_table(m_thd, m_failed_table);
+ m_thd->mdl_context.release_transactional_locks();
break;
}
default:
@@ -4364,7 +4364,7 @@ restart:
TABLE_LIST element. Altough currently this assumption is valid
it may change in future.
*/
- if (ot_ctx.recover_from_failed_open(thd))
+ if (ot_ctx.recover_from_failed_open())
goto err;
/* Re-open temporary tables after close_tables_for_reopen(). */
@@ -4421,7 +4421,7 @@ restart:
{
close_tables_for_reopen(thd, start,
ot_ctx.start_of_statement_svp());
- if (ot_ctx.recover_from_failed_open(thd))
+ if (ot_ctx.recover_from_failed_open())
goto err;
/* Re-open temporary tables after close_tables_for_reopen(). */
@@ -4867,7 +4867,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
*/
thd->mdl_context.rollback_to_savepoint(ot_ctx.start_of_statement_svp());
table_list->mdl_request.ticket= 0;
- if (ot_ctx.recover_from_failed_open(thd))
+ if (ot_ctx.recover_from_failed_open())
break;
}
@@ -6184,9 +6184,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, 1, (uchar *) 0);
+ it->walk(&Item::register_field_in_read_map, 0, (uchar *) 0);
else
- it->walk(&Item::register_field_in_write_map, 1, (uchar *) 0);
+ it->walk(&Item::register_field_in_write_map, 0, (uchar *) 0);
}
}
else
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 09da848e77d..3e633fad084 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -504,7 +504,7 @@ public:
};
Open_table_context(THD *thd, uint flags);
- bool recover_from_failed_open(THD *thd);
+ bool recover_from_failed_open();
bool request_backoff_action(enum_open_table_action action_arg,
TABLE_LIST *table);
@@ -544,6 +544,8 @@ public:
}
private:
+ /* THD for which tables are opened. */
+ THD *m_thd;
/**
For OT_DISCOVER and OT_REPAIR actions, the table list element for
the table which definition should be re-discovered or which
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 97034878eef..5307f4f01f8 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2010, 2012, Monty Program Ab.
+/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2013, Monty Program Ab
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
@@ -2090,7 +2090,12 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
*/
thd->query_cache_is_applicable= 0; // Query can't be cached
}
- /* End the statement transaction potentially started by engine. */
+ /*
+ End the statement transaction potentially started by engine.
+ Currently our engines do not request rollback from callbacks.
+ If this is going to change code needs to be reworked.
+ */
+ DBUG_ASSERT(! thd->transaction_rollback_request);
trans_rollback_stmt(thd);
goto err_unlock; // Parse query
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 2316dee3aee..eef5671f9c3 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -4191,6 +4191,10 @@ extern "C" unsigned long thd_get_thread_id(const MYSQL_THD thd)
return((unsigned long)thd->thread_id);
}
+extern "C" enum_tx_isolation thd_get_trx_isolation(const MYSQL_THD thd)
+{
+ return thd->tx_isolation;
+}
/**
Check if THD socket is still connected.
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 25090ee596a..19c1ac8f4b6 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2009, 2013, Monty Program Ab.
This program is free software; you can redistribute it and/or modify
@@ -463,6 +462,7 @@ enum killed_type
#include "sql_lex.h" /* Must be here */
+extern LEX_STRING sql_statement_names[(uint) SQLCOM_END + 1];
class Delayed_insert;
class select_result;
class Time_zone;
@@ -3290,7 +3290,11 @@ public:
*/
bool set_db(const char *new_db, size_t new_db_len)
{
- bool result;
+ /*
+ Acquiring mutex LOCK_thd_data as we either free the memory allocated
+ for the database and reallocating the memory for the new db or memcpy
+ the new_db to the db.
+ */
mysql_mutex_lock(&LOCK_thd_data);
/* Do not reallocate memory if current chunk is big enough. */
if (db && new_db && db_length >= new_db_len)
@@ -3304,7 +3308,7 @@ public:
db= NULL;
}
db_length= db ? new_db_len : 0;
- result= new_db && !db;
+ bool result= new_db && !db;
mysql_mutex_unlock(&LOCK_thd_data);
#ifdef HAVE_PSI_THREAD_INTERFACE
if (result)
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 8db305e45c5..8068901ebec 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2009, 2013, Monty Program Ab.
This program is free software; you can redistribute it and/or modify
@@ -1254,8 +1254,7 @@ static void mysql_change_db_impl(THD *thd,
we just call THD::reset_db(). Since THD::reset_db() does not releases
the previous database name, we should do it explicitly.
*/
- my_free(thd->db);
-
+ thd->set_db(NULL, 0);
thd->reset_db(new_db_name->str, new_db_name->length);
}
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 4187327d622..812a5dc1461 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -791,7 +791,10 @@ retry:
/*
Always close statement transaction explicitly,
so that the engine doesn't have to count locks.
+ There should be no need to perform transaction
+ rollback due to deadlock.
*/
+ DBUG_ASSERT(! thd->transaction_rollback_request);
trans_rollback_stmt(thd);
mysql_ha_close_table(handler);
if (thd->stmt_arena->is_stmt_execute())
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index f50953e4103..2110f81dd4f 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -197,6 +197,7 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex)
table->map= 1; //To ensure correct calculation of const item
table->get_fields_in_item_tree= TRUE;
table_list->table= table;
+ table_list->cacheable_table= false;
return FALSE;
}
@@ -3864,7 +3865,7 @@ void SELECT_LEX::update_used_tables()
}
for (ORDER *order= group_list.first; order; order= order->next)
(*order->item)->update_used_tables();
- if (!master_unit()->is_union())
+ if (!master_unit()->is_union() || master_unit()->global_parameters != this)
{
for (ORDER *order= order_list.first; order; order= order->next)
(*order->item)->update_used_tables();
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index f892f1bf3c7..479fa81edd7 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -636,7 +636,7 @@ public:
void print(String *str, enum_query_type query_type);
bool add_fake_select_lex(THD *thd);
- void init_prepare_fake_select_lex(THD *thd);
+ void init_prepare_fake_select_lex(THD *thd, bool first_execution);
inline bool is_prepared() { return prepared; }
bool change_result(select_result_interceptor *result,
select_result_interceptor *old_result);
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index 7ef320b30d2..0771f569f35 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -140,9 +140,12 @@ void start_handle_manager()
if (flush_time && flush_time != ~(ulong) 0L)
{
pthread_t hThread;
- if (mysql_thread_create(key_thread_handle_manager,
- &hThread, &connection_attrib, handle_manager, 0))
- sql_print_warning("Can't create handle_manager thread");
+ int error;
+ if ((error= mysql_thread_create(key_thread_handle_manager,
+ &hThread, &connection_attrib,
+ handle_manager, 0)))
+ sql_print_warning("Can't create handle_manager thread (errno= %d)",
+ error);
}
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 2036cd1b373..f9bfa6d120b 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
Copyright (c) 2008, 2013, Monty Program Ab
This program is free software; you can redistribute it and/or modify
@@ -1468,6 +1468,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
close_thread_tables(thd);
thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+ if (thd->transaction_rollback_request)
+ {
+ /*
+ Transaction rollback was requested since MDL deadlock was
+ discovered while trying to open tables. Rollback transaction
+ in all storage engines including binary log and release all
+ locks.
+ */
+ trans_rollback_implicit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+
thd->cleanup_after_query();
break;
}
@@ -1763,7 +1775,7 @@ void log_slow_statement(THD *thd)
statement in a trigger or stored function
*/
if (unlikely(thd->in_sub_stmt))
- DBUG_VOID_RETURN; // Don't set time for sub stmt
+ goto end; // Don't set time for sub stmt
/* Follow the slow log filter configuration. */
@@ -1771,8 +1783,7 @@ void log_slow_statement(THD *thd)
(thd->variables.log_slow_filter
&& !(thd->variables.log_slow_filter & thd->query_plan_flags)))
{
- delete_explain_query(thd->lex);
- DBUG_VOID_RETURN;
+ goto end;
}
if (((thd->server_status & SERVER_QUERY_WAS_SLOW) ||
@@ -1789,13 +1800,14 @@ void log_slow_statement(THD *thd)
*/
if (thd->variables.log_slow_rate_limit > 1 &&
(global_query_id % thd->variables.log_slow_rate_limit) != 0)
- DBUG_VOID_RETURN;
+ goto end;
THD_STAGE_INFO(thd, stage_logging_slow_query);
slow_log_print(thd, thd->query(), thd->query_length(),
thd->utime_after_query);
}
+end:
delete_explain_query(thd->lex);
DBUG_VOID_RETURN;
}
@@ -2161,7 +2173,7 @@ err:
can free its locks if LOCK TABLES locked some tables before finding
that it can't lock a table in its list
*/
- trans_commit_implicit(thd);
+ trans_rollback(thd);
/* Close tables and release metadata locks. */
close_thread_tables(thd);
DBUG_ASSERT(!thd->locked_tables_mode);
@@ -2215,6 +2227,13 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt);
/*
+ Each statement or replication event which might produce deadlock
+ should handle transaction rollback on its own. So by the start of
+ the next statement transaction rollback request should be fulfilled
+ already.
+ */
+ DBUG_ASSERT(! thd->transaction_rollback_request || thd->in_sub_stmt);
+ /*
In many cases first table of main SELECT_LEX have special meaning =>
check that it is first table in global list and relink it first in
queries_tables list if it is necessary (we need such relinking only
@@ -2418,8 +2437,8 @@ mysql_execute_command(THD *thd)
or triggers as all such statements prohibited there.
*/
DBUG_ASSERT(! thd->in_sub_stmt);
- /* Commit or rollback the statement transaction. */
- thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ /* Statement transaction still should not be started. */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty());
/* Commit the normal transaction if one is active. */
if (trans_commit_implicit(thd))
goto error;
@@ -5117,7 +5136,17 @@ finish:
thd->set_binlog_format(orig_binlog_format,
orig_current_stmt_binlog_format);
- if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END))
+ if (! thd->in_sub_stmt && thd->transaction_rollback_request)
+ {
+ /*
+ We are not in sub-statement and transaction rollback was requested by
+ one of storage engines (e.g. due to deadlock). Rollback transaction in
+ all storage engines including binary log.
+ */
+ trans_rollback_implicit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+ else if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END))
{
/* No transaction control allowed in sub-statements. */
DBUG_ASSERT(! thd->in_sub_stmt);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 7e038bf28f0..62c935db544 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2002, 2012, Oracle and/or its affiliates.
- Copyright (c) 2008, 2011, Monty Program Ab
+/* Copyright (c) 2002, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2013, Monty Program Ab
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
@@ -116,6 +116,7 @@ When one supplies long data for a placeholder:
#endif
#include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL
#include "sql_handler.h"
+#include "transaction.h" // trans_rollback_implicit
/**
A result class used to send cursor rows using the binary protocol.
@@ -3439,6 +3440,22 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
close_thread_tables(thd);
thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
+
+ /*
+ Transaction rollback was requested since MDL deadlock was discovered
+ while trying to open tables. Rollback transaction in all storage
+ engines including binary log and release all locks.
+
+ Once dynamic SQL is allowed as substatements the below if-statement
+ has to be adjusted to not do rollback in substatement.
+ */
+ DBUG_ASSERT(! thd->in_sub_stmt);
+ if (thd->transaction_rollback_request)
+ {
+ trans_rollback_implicit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+
lex_end(lex);
cleanup_stmt();
thd->restore_backup_statement(this, &stmt_backup);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 5d508b56dac..717201d5dcc 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1575,7 +1575,7 @@ send_event_to_slave(THD *thd, NET *net, String* const packet, ushort flags,
DBUG_EXECUTE_IF("gtid_force_reconnect_at_10_1_100",
{
rpl_gtid *dbug_gtid;
- if ((dbug_gtid= until_binlog_state->find(10,1)) &&
+ if ((dbug_gtid= until_binlog_state->find_nolock(10,1)) &&
dbug_gtid->seq_no == 100)
{
DBUG_SET("-d,gtid_force_reconnect_at_10_1_100");
@@ -1585,7 +1585,7 @@ send_event_to_slave(THD *thd, NET *net, String* const packet, ushort flags,
}
});
- if (until_binlog_state->update(&event_gtid, false))
+ if (until_binlog_state->update_nolock(&event_gtid, false))
{
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
return "Failed in internal GTID book-keeping: Out of memory";
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index f5cfbf8ffd1..c109ee10877 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -241,7 +241,8 @@ static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array,
List<Item> &all_fields,
bool *all_order_by_fields_used);
static bool test_if_subpart(ORDER *a,ORDER *b);
-static TABLE *get_sort_by_table(ORDER *a,ORDER *b,List<TABLE_LIST> &tables);
+static TABLE *get_sort_by_table(ORDER *a,ORDER *b,List<TABLE_LIST> &tables,
+ table_map const_tables);
static void calc_group_buffer(JOIN *join,ORDER *group);
static bool make_group_fields(JOIN *main_join, JOIN *curr_join);
static bool alloc_group_fields(JOIN *join,ORDER *group);
@@ -1319,7 +1320,8 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S
goto setup_subq_exit;
}
error= -1; // Error is sent to client
- sort_by_table= get_sort_by_table(order, group_list, select_lex->leaf_tables);
+ /* get_sort_by_table() call used to be here: */
+ MEM_UNDEFINED(&sort_by_table, sizeof(sort_by_table));
/* Calculate how to do the join */
THD_STAGE_INFO(thd, stage_statistics);
@@ -3686,7 +3688,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
// All dep. must be constants
if (s->dependent & ~(found_const_table_map))
continue;
- if (table->stat_records() <= 1L &&
+ if (table->file->stats.records <= 1L &&
(table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
!table->pos_in_table_list->embedding &&
!((outer_join & table->map) &&
@@ -3798,6 +3800,9 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
}
} while (join->const_table_map & found_ref && ref_changed);
+ join->sort_by_table= get_sort_by_table(join->order, join->group_list,
+ join->select_lex->leaf_tables,
+ join->const_table_map);
/*
Update info on indexes that can be used for search lookups as
reading const tables may has added new sargable predicates.
@@ -3828,6 +3833,21 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
conds=new Item_int((longlong) 0,1);
}
join->conds= conds;
+ join->cond_equal= NULL;
+ if (conds)
+ {
+ if (conds->type() == Item::COND_ITEM &&
+ ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC)
+ join->cond_equal= (&((Item_cond_and *) conds)->cond_equal);
+ else if (conds->type() == Item::FUNC_ITEM &&
+ ((Item_func*) conds)->functype() == Item_func::MULT_EQUAL_FUNC)
+ {
+ if (!join->cond_equal)
+ join->cond_equal= new COND_EQUAL;
+ join->cond_equal->current_level.empty();
+ join->cond_equal->current_level.push_back((Item_equal*) conds);
+ }
+ }
}
/* Calc how many (possible) matched records in each table */
@@ -3964,6 +3984,19 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
if (join->const_tables != join->table_count)
optimize_keyuse(join, keyuse_array);
+ DBUG_ASSERT(!join->conds || !join->cond_equal ||
+ !join->cond_equal->current_level.elements ||
+ (join->conds->type() == Item::COND_ITEM &&
+ ((Item_cond*) (join->conds))->functype() ==
+ Item_func::COND_AND_FUNC &&
+ join->cond_equal ==
+ &((Item_cond_and *) (join->conds))->cond_equal) ||
+ (join->conds->type() == Item::FUNC_ITEM &&
+ ((Item_func*) (join->conds))->functype() ==
+ Item_func::MULT_EQUAL_FUNC &&
+ join->cond_equal->current_level.elements == 1 &&
+ join->cond_equal->current_level.head() == join->conds));
+
if (optimize_semijoin_nests(join, all_table_map))
DBUG_RETURN(TRUE); /* purecov: inspected */
@@ -10908,7 +10941,23 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
join->group_list ?
join->join_tab+join->const_tables :
join->get_sort_by_join_tab();
- if (sort_by_tab)
+ /*
+ It could be that sort_by_tab==NULL, and the plan is to use filesort()
+ on the first table.
+ */
+ if (join->order)
+ {
+ join->simple_order= 0;
+ join->need_tmp= 1;
+ }
+
+ if (join->group && !join->group_optimized_away)
+ {
+ join->need_tmp= 1;
+ join->simple_group= 0;
+ }
+
+ if (sort_by_tab)
{
join->need_tmp= 1;
join->simple_order= join->simple_group= 0;
@@ -11399,17 +11448,18 @@ void JOIN::cleanup(bool full)
tabs_kind= WALK_EXECUTION_TABS;
if (table_count)
{
- for (tab= first_breadth_first_tab(this, tabs_kind); tab;
+ for (tab= first_breadth_first_tab(this, tabs_kind); tab;
tab= next_breadth_first_tab(this, tabs_kind, tab))
{
tab->cleanup();
}
}
cleaned= true;
+
}
else
{
- for (tab= first_linear_tab(this, WITH_CONST_TABLES); tab;
+ for (tab= first_linear_tab(this, WITH_CONST_TABLES); tab;
tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
if (tab->table)
@@ -14401,16 +14451,44 @@ internal_remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
{
if (cond->type() == Item::COND_ITEM)
{
- List<Item_equal> new_equalities;
bool and_level= ((Item_cond*) cond)->functype()
== Item_func::COND_AND_FUNC;
List<Item> *cond_arg_list= ((Item_cond*) cond)->argument_list();
+
+ if (and_level)
+ {
+ /*
+ Remove multiple equalities that became always true (e.g. after
+ constant row substitution).
+ They would be removed later in the function anyway, but the list of
+ them cond_equal.current_level also must be adjusted correspondingly.
+ So it's easier to do it at one pass through the list of the equalities.
+ */
+ List<Item_equal> *cond_equalities=
+ &((Item_cond_and *) cond)->cond_equal.current_level;
+ cond_arg_list->disjoin((List<Item> *) cond_equalities);
+ List_iterator<Item_equal> it(*cond_equalities);
+ Item_equal *eq_item;
+ while ((eq_item= it++))
+ {
+ if (eq_item->const_item() && eq_item->val_int())
+ it.remove();
+ }
+ cond_arg_list->concat((List<Item> *) cond_equalities);
+ }
+
+ List<Item_equal> new_equalities;
List_iterator<Item> li(*cond_arg_list);
+ bool should_fix_fields= 0;
Item::cond_result tmp_cond_value;
- bool should_fix_fields=0;
-
- *cond_value=Item::COND_UNDEF;
Item *item;
+
+ /*
+ If the list cond_arg_list became empty then it consisted only
+ of always true multiple equalities.
+ */
+ *cond_value= cond_arg_list->elements ? Item::COND_UNDEF : Item::COND_TRUE;
+
while ((item=li++))
{
Item *new_item=internal_remove_eq_conds(thd, item, &tmp_cond_value);
@@ -21284,7 +21362,8 @@ test_if_subpart(ORDER *a,ORDER *b)
*/
static TABLE *
-get_sort_by_table(ORDER *a,ORDER *b, List<TABLE_LIST> &tables)
+get_sort_by_table(ORDER *a,ORDER *b, List<TABLE_LIST> &tables,
+ table_map const_tables)
{
TABLE_LIST *table;
List_iterator<TABLE_LIST> ti(tables);
@@ -21298,6 +21377,23 @@ get_sort_by_table(ORDER *a,ORDER *b, List<TABLE_LIST> &tables)
for (; a && b; a=a->next,b=b->next)
{
+ /* Skip elements of a that are constant */
+ while (!((*a->item)->used_tables() & ~const_tables))
+ {
+ if (!(a= a->next))
+ break;
+ }
+
+ /* Skip elements of b that are constant */
+ while (!((*b->item)->used_tables() & ~const_tables))
+ {
+ if (!(b= b->next))
+ break;
+ }
+
+ if (!a || !b)
+ break;
+
if (!(*a->item)->eq(*b->item,1))
DBUG_RETURN(0);
map|=a->item[0]->used_tables();
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 82fbf3b124a..17767a2afb3 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2612,7 +2612,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
{
Security_context *tmp_sctx= tmp->security_ctx;
struct st_my_thread_var *mysys_var;
- const char *val;
+ const char *val, *db;
ulonglong max_counter;
if ((!tmp->vio_ok() && !tmp->system_thread) ||
@@ -2639,13 +2639,13 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
table->field[2]->store(tmp_sctx->host_or_ip,
strlen(tmp_sctx->host_or_ip), cs);
/* DB */
- if (tmp->db)
+ mysql_mutex_lock(&tmp->LOCK_thd_data);
+ if ((db= tmp->db))
{
- table->field[3]->store(tmp->db, strlen(tmp->db), cs);
+ table->field[3]->store(db, strlen(db), cs);
table->field[3]->set_notnull();
}
- mysql_mutex_lock(&tmp->LOCK_thd_data);
if ((mysys_var= tmp->mysys_var))
mysql_mutex_lock(&mysys_var->mutex);
/* COMMAND */
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index e0e778a6baf..45d9c5dc091 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2207,6 +2207,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
bool non_tmp_error= 0;
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
bool non_tmp_table_deleted= 0;
+ bool is_drop_tmp_if_exists_added= 0;
String built_query;
String built_trans_tmp_query, built_non_trans_tmp_query;
DBUG_ENTER("mysql_rm_table_no_locks");
@@ -2236,6 +2237,15 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
table stems from the fact that such drop does not commit an ongoing
transaction and changes to non-transactional tables must be written
ahead of the transaction in some circumstances.
+
+ 6- Slave SQL thread ignores all replicate-* filter rules
+ for temporary tables with 'IF EXISTS' clause. (See sql/sql_parse.cc:
+ mysql_execute_command() for details). These commands will be binlogged
+ as they are, even if the default database (from USE `db`) is not present
+ on the Slave. This can cause point in time recovery failures later
+ when user uses the slave's binlog to re-apply. Hence at the time of binary
+ logging, these commands will be written with fully qualified table names
+ and use `db` will be suppressed.
*/
if (!dont_log_query)
{
@@ -2259,6 +2269,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
if (thd->is_current_stmt_binlog_format_row() || if_exists)
{
+ is_drop_tmp_if_exists_added= true;
built_trans_tmp_query.set_charset(system_charset_info);
built_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
built_non_trans_tmp_query.set_charset(system_charset_info);
@@ -2335,10 +2346,12 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
String *built_ptr_query=
(is_trans ? &built_trans_tmp_query : &built_non_trans_tmp_query);
/*
- Don't write the database name if it is the current one (or if
- thd->db is NULL).
+ Write the database name if it is not the current one or if
+ thd->db is NULL or 'IF EXISTS' clause is present in 'DROP TEMPORARY'
+ query.
*/
- if (thd->db == NULL || strcmp(db,thd->db) != 0)
+ if (thd->db == NULL || strcmp(db,thd->db) != 0
+ || is_drop_tmp_if_exists_added )
{
append_identifier(thd, built_ptr_query, db, db_length);
built_ptr_query->append(".");
@@ -2553,7 +2566,9 @@ err:
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
built_non_trans_tmp_query.ptr(),
built_non_trans_tmp_query.length(),
- FALSE, FALSE, FALSE, 0);
+ FALSE, FALSE,
+ is_drop_tmp_if_exists_added,
+ 0);
}
if (trans_tmp_table_deleted)
{
@@ -2563,7 +2578,9 @@ err:
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
built_trans_tmp_query.ptr(),
built_trans_tmp_query.length(),
- TRUE, FALSE, FALSE, 0);
+ TRUE, FALSE,
+ is_drop_tmp_if_exists_added,
+ 0);
}
if (non_tmp_table_deleted)
{
@@ -5202,7 +5219,6 @@ int mysql_discard_or_import_tablespace(THD *thd,
error= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
err:
- trans_rollback_stmt(thd);
thd->tablespace_op=FALSE;
if (error == 0)
@@ -9059,6 +9075,12 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
Protocol *protocol= thd->protocol;
DBUG_ENTER("mysql_checksum_table");
+ /*
+ CHECKSUM TABLE returns results and rollbacks statement transaction,
+ so it should not be used in stored function or trigger.
+ */
+ DBUG_ASSERT(! thd->in_sub_stmt);
+
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
item->maybe_null= 1;
field_list.push_back(item= new Item_int("Checksum",
@@ -9097,7 +9119,6 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
open_and_lock_tables(thd, table, FALSE, 0))
{
t= NULL;
- thd->clear_error(); // these errors shouldn't get client
}
else
t= table->table;
@@ -9111,7 +9132,6 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
{
/* Table didn't exist */
protocol->store_null();
- thd->clear_error();
}
else
{
@@ -9199,11 +9219,24 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
t->file->ha_rnd_end();
}
}
- thd->clear_error();
- if (! thd->in_sub_stmt)
- trans_rollback_stmt(thd);
+ trans_rollback_stmt(thd);
close_thread_tables(thd);
}
+
+ if (thd->transaction_rollback_request)
+ {
+ /*
+ If transaction rollback was requested we honor it. To do this we
+ abort statement and return error as not only CHECKSUM TABLE is
+ rolled back but the whole transaction in which it was used.
+ */
+ thd->protocol->remove_last_row();
+ goto err;
+ }
+
+ /* Hide errors from client. Return NULL for problematic tables instead. */
+ thd->clear_error();
+
if (protocol->write())
goto err;
}
diff --git a/sql/sql_time.cc b/sql/sql_time.cc
index 831a7fa2a20..b194d46643e 100644
--- a/sql/sql_time.cc
+++ b/sql/sql_time.cc
@@ -1100,3 +1100,22 @@ int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b)
return 0;
}
+
+/*
+ Convert a TIME value to DAY-TIME interval, e.g. for extraction:
+ EXTRACT(DAY FROM x), EXTRACT(HOUR FROM x), etc.
+ Moves full days from ltime->hour to ltime->day.
+ Note, time_type is set to MYSQL_TIMESTAMP_NONE, to make sure that
+ the structure is not used for anything else other than extraction:
+ non-extraction TIME functions expect zero day value!
+*/
+void time_to_daytime_interval(MYSQL_TIME *ltime)
+{
+ DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_TIME);
+ DBUG_ASSERT(ltime->year == 0);
+ DBUG_ASSERT(ltime->month == 0);
+ DBUG_ASSERT(ltime->day == 0);
+ ltime->day= ltime->hour / 24;
+ ltime->hour%= 24;
+ ltime->time_type= MYSQL_TIMESTAMP_NONE;
+}
diff --git a/sql/sql_time.h b/sql/sql_time.h
index 928e257ab54..6a8c78ecd5e 100644
--- a/sql/sql_time.h
+++ b/sql/sql_time.h
@@ -33,6 +33,7 @@ typedef struct st_known_date_time_format KNOWN_DATE_TIME_FORMAT;
ulong convert_period_to_month(ulong period);
ulong convert_month_to_period(ulong month);
+void time_to_daytime_interval(MYSQL_TIME *l_time);
bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code);
bool str_to_datetime_with_warn(CHARSET_INFO *cs, const char *str,
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index b046b3a4de8..d143930908d 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -193,13 +193,15 @@ void select_union::cleanup()
SYNOPSIS
st_select_lex_unit::init_prepare_fake_select_lex()
thd - thread handler
+ first_execution - TRUE at the first execution of the union
RETURN
options of SELECT
*/
void
-st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg)
+st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg,
+ bool first_execution)
{
thd_arg->lex->current_select= fake_select_lex;
fake_select_lex->table_list.link_in_list(&result_table_list,
@@ -207,7 +209,13 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg)
fake_select_lex->context.table_list=
fake_select_lex->context.first_name_resolution_table=
fake_select_lex->get_table_list();
- if (!fake_select_lex->first_execution)
+ /*
+ The flag fake_select_lex->first_execution indicates whether this is
+ called at the first execution of the statement, while first_execution
+ shows whether this is called at the first execution of the union that
+ may form just a subselect.
+ */
+ if (!fake_select_lex->first_execution && first_execution)
{
for (ORDER *order= global_parameters->order_list.first;
order;
@@ -481,7 +489,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
{
/* Validate the global parameters of this union */
- init_prepare_fake_select_lex(thd);
+ init_prepare_fake_select_lex(thd, TRUE);
/* Should be done only once (the only item_list per statement) */
DBUG_ASSERT(fake_select_lex->join == 0);
if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->variables.option_bits,
@@ -622,6 +630,7 @@ bool st_select_lex_unit::exec()
SELECT_LEX *select_cursor=first_select();
ulonglong add_rows=0;
ha_rows examined_rows= 0;
+ bool first_execution= !executed;
DBUG_ENTER("st_select_lex_unit::exec");
bool was_executed= executed;
@@ -644,6 +653,7 @@ bool st_select_lex_unit::exec()
{
ha_rows records_at_start= 0;
thd->lex->current_select= sl;
+ fake_select_lex->uncacheable|= sl->uncacheable;
{
set_limit(sl);
@@ -750,7 +760,7 @@ bool st_select_lex_unit::exec()
if (!thd->is_fatal_error) // Check if EOM
{
set_limit(global_parameters);
- init_prepare_fake_select_lex(thd);
+ init_prepare_fake_select_lex(thd, first_execution);
JOIN *join= fake_select_lex->join;
if (!join)
{
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 09ce9c37e2d..e1c92a81604 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1443,7 +1443,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
objects of the view.
*/
if (!(table->view_sctx= (Security_context *)
- thd->stmt_arena->alloc(sizeof(Security_context))))
+ thd->stmt_arena->calloc(sizeof(Security_context))))
goto err;
security_ctx= table->view_sctx;
}
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 97ddedf2353..edd6e7b12a4 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -829,6 +829,7 @@ static bool event_scheduler_check(sys_var *self, THD *thd, set_var *var)
}
static bool event_scheduler_update(sys_var *self, THD *thd, enum_var_type type)
{
+ int err_no= 0;
uint opt_event_scheduler_value= Events::opt_event_scheduler;
mysql_mutex_unlock(&LOCK_global_system_variables);
/*
@@ -848,11 +849,14 @@ static bool event_scheduler_update(sys_var *self, THD *thd, enum_var_type type)
for deadlocks. See bug#51160.
*/
bool ret= opt_event_scheduler_value == Events::EVENTS_ON
- ? Events::start()
+ ? Events::start(&err_no)
: Events::stop();
mysql_mutex_lock(&LOCK_global_system_variables);
if (ret)
- my_error(ER_EVENT_SET_VAR_ERROR, MYF(0), my_errno);
+ {
+ Events::opt_event_scheduler= Events::EVENTS_OFF;
+ my_error(ER_EVENT_SET_VAR_ERROR, MYF(0), err_no);
+ }
return ret;
}
diff --git a/sql/table.cc b/sql/table.cc
index 84f929fa7a7..a4065f2c393 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -5066,10 +5066,8 @@ TABLE *TABLE_LIST::get_real_join_table()
*/
for (TABLE_LIST *t= ti++; t; t= ti++)
tbl= t;
- /*
- It is impossible that the list is empty
- so tbl can't be NULL after above loop.
- */
+ if (!tbl)
+ return NULL; // view/derived with no tables
if (!tbl->nested_join)
break;
/* go deeper if we've found nested join */
diff --git a/sql/transaction.cc b/sql/transaction.cc
index a293ab9d5f9..256351ee373 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -310,6 +310,52 @@ bool trans_rollback(THD *thd)
/**
+ Implicitly rollback the current transaction, typically
+ after deadlock was discovered.
+
+ @param thd Current thread
+
+ @retval False Success
+ @retval True Failure
+
+ @note ha_rollback_low() which is indirectly called by this
+ function will mark XA transaction for rollback by
+ setting appropriate RM error status if there was
+ transaction rollback request.
+*/
+
+bool trans_rollback_implicit(THD *thd)
+{
+ int res;
+ DBUG_ENTER("trans_rollback_implict");
+
+ /*
+ Always commit/rollback statement transaction before manipulating
+ with the normal one.
+ Don't perform rollback in the middle of sub-statement, wait till
+ its end.
+ */
+ DBUG_ASSERT(thd->transaction.stmt.is_empty() && !thd->in_sub_stmt);
+
+ thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+ DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS"));
+ res= ha_rollback_trans(thd, true);
+ /*
+ We don't reset OPTION_BEGIN flag below to simulate implicit start
+ of new transacton in @@autocommit=1 mode. This is necessary to
+ preserve backward compatibility.
+ */
+ thd->variables.option_bits&= ~(OPTION_KEEP_LOG);
+ thd->transaction.all.modified_non_trans_table= false;
+
+ /* Rollback should clear transaction_rollback_request flag. */
+ DBUG_ASSERT(! thd->transaction_rollback_request);
+
+ DBUG_RETURN(test(res));
+}
+
+
+/**
Commit the single statement transaction.
@note Note that if the autocommit is on, then the following call
@@ -384,8 +430,6 @@ bool trans_rollback_stmt(THD *thd)
if (thd->transaction.stmt.ha_list)
{
ha_rollback_trans(thd, FALSE);
- if (thd->transaction_rollback_request && !thd->in_sub_stmt)
- ha_rollback_trans(thd, TRUE);
if (! thd->in_active_multi_stmt_transaction())
{
thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
diff --git a/sql/transaction.h b/sql/transaction.h
index e002cd4a9dc..abe7823cf9b 100644
--- a/sql/transaction.h
+++ b/sql/transaction.h
@@ -30,6 +30,7 @@ bool trans_begin(THD *thd, uint flags= 0);
bool trans_commit(THD *thd);
bool trans_commit_implicit(THD *thd);
bool trans_rollback(THD *thd);
+bool trans_rollback_implicit(THD *thd);
bool trans_commit_stmt(THD *thd);
bool trans_rollback_stmt(THD *thd);
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 272dfb6381b..2026ed425f2 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -2495,13 +2495,14 @@ char *root_name_end;
*/
my_bool
-scan_tz_dir(char * name_end)
+scan_tz_dir(char * name_end, uint symlink_recursion_level)
{
MY_DIR *cur_dir;
char *name_end_tmp;
uint i;
- if (!(cur_dir= my_dir(fullname, MYF(MY_WANT_STAT))))
+ /* Sort directory data, to pass mtr tests on different platforms. */
+ if (!(cur_dir= my_dir(fullname, MYF(MY_WANT_STAT|MY_WANT_SORT))))
return 1;
name_end= strmake(name_end, "/", FN_REFLEN - (name_end - fullname));
@@ -2515,7 +2516,32 @@ scan_tz_dir(char * name_end)
if (MY_S_ISDIR(cur_dir->dir_entry[i].mystat->st_mode))
{
- if (scan_tz_dir(name_end_tmp))
+ my_bool is_symlink;
+ if ((is_symlink= my_is_symlink(fullname)) &&
+ symlink_recursion_level > 0)
+ {
+ /*
+ The timezone definition data in some Linux distributions
+ (e.g. the "timezone-data-2013f" package in Gentoo)
+ may have synlimks like:
+ /usr/share/zoneinfo/posix/ -> /usr/share/zoneinfo/,
+ so the same timezone files are available under two names
+ (e.g. "CET" and "posix/CET").
+
+ We allow one level of symlink recursion for backward
+ compatibility with earlier timezone data packages that have
+ duplicate copies of the same timezone files inside the root
+ directory and the "posix" subdirectory (instead of symlinking).
+ This makes "posix/CET" still available, but helps to avoid
+ following such symlinks infinitely:
+ /usr/share/zoneinfo/posix/posix/posix/.../posix/
+ */
+ fflush(stdout);
+ fprintf(stderr, "Warning: Skipping directory '%s': "
+ "to avoid infinite symlink recursion.\n", fullname);
+ continue;
+ }
+ if (scan_tz_dir(name_end_tmp, symlink_recursion_level + is_symlink))
{
my_dirend(cur_dir);
return 1;
@@ -2527,14 +2553,20 @@ scan_tz_dir(char * name_end)
if (!tz_load(fullname, &tz_info, &tz_storage))
print_tz_as_sql(root_name_end + 1, &tz_info);
else
+ {
+ fflush(stdout);
fprintf(stderr,
"Warning: Unable to load '%s' as time zone. Skipping it.\n",
fullname);
+ }
free_root(&tz_storage, MYF(0));
}
else
+ {
+ fflush(stdout);
fprintf(stderr, "Warning: '%s' is not regular file or directory\n",
fullname);
+ }
}
}
@@ -2567,8 +2599,9 @@ main(int argc, char **argv)
printf("TRUNCATE TABLE time_zone_transition;\n");
printf("TRUNCATE TABLE time_zone_transition_type;\n");
- if (scan_tz_dir(root_name_end))
+ if (scan_tz_dir(root_name_end, 0))
{
+ fflush(stdout);
fprintf(stderr, "There were fatal errors during processing "
"of zoneinfo directory\n");
return 1;
@@ -2587,6 +2620,7 @@ main(int argc, char **argv)
{
if (tz_load(argv[2], &tz_info, &tz_storage))
{
+ fflush(stdout);
fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
return 1;
}
@@ -2596,6 +2630,7 @@ main(int argc, char **argv)
{
if (tz_load(argv[1], &tz_info, &tz_storage))
{
+ fflush(stdout);
fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
return 1;
}
@@ -2605,6 +2640,7 @@ main(int argc, char **argv)
free_root(&tz_storage, MYF(0));
}
+ my_end(0);
return 0;
}