summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2014-02-03 15:22:39 +0100
committerSergei Golubchik <sergii@pisem.net>2014-02-03 15:22:39 +0100
commit72c20282db820b0b0818aea160a485bdca897eec (patch)
tree3089e022d958990fc0a405a38ba43ae00c87103c /sql
parent5e1d5d9bc0bf9ea776bffe6c4914a84be920c0b2 (diff)
parent2acc01b3cfa27074f93016b893cda20fa0a3497f (diff)
downloadmariadb-git-72c20282db820b0b0818aea160a485bdca897eec.tar.gz
10.0-base merge
Diffstat (limited to 'sql')
-rw-r--r--sql/ha_partition.cc25
-rw-r--r--sql/ha_partition.h3
-rw-r--r--sql/handler.cc22
-rw-r--r--sql/item.cc54
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_func.cc12
-rw-r--r--sql/item_strfunc.cc11
-rw-r--r--sql/item_strfunc.h2
-rw-r--r--sql/item_sum.cc8
-rw-r--r--sql/item_timefunc.cc22
-rw-r--r--sql/log.cc166
-rw-r--r--sql/log.h2
-rw-r--r--sql/log_event.cc6
-rw-r--r--sql/mysqld.cc27
-rw-r--r--sql/mysqld.h3
-rw-r--r--sql/net_serv.cc4
-rw-r--r--sql/opt_range.cc19
-rw-r--r--sql/opt_subselect.cc2
-rw-r--r--sql/partition_info.cc6
-rw-r--r--sql/partition_info.h2
-rw-r--r--sql/records.cc3
-rw-r--r--sql/rpl_parallel.cc96
-rw-r--r--sql/rpl_rli.cc6
-rw-r--r--sql/set_var.cc6
-rw-r--r--sql/set_var.h3
-rw-r--r--sql/share/errmsg-utf8.txt50
-rw-r--r--sql/slave.cc23
-rw-r--r--sql/sql_admin.cc5
-rw-r--r--sql/sql_base.cc70
-rw-r--r--sql/sql_class.cc65
-rw-r--r--sql/sql_class.h37
-rw-r--r--sql/sql_derived.cc17
-rw-r--r--sql/sql_insert.cc12
-rw-r--r--sql/sql_lex.cc28
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_parse.cc9
-rw-r--r--sql/sql_partition.cc2
-rw-r--r--sql/sql_plugin.cc151
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_select.cc105
-rw-r--r--sql/sql_show.cc7
-rw-r--r--sql/sql_time.cc14
-rw-r--r--sql/sql_time.h1
-rw-r--r--sql/sql_union.cc5
-rw-r--r--sql/sql_view.cc6
-rw-r--r--sql/sql_yacc.yy4
-rw-r--r--sql/sys_vars.cc38
-rw-r--r--sql/table.cc17
-rw-r--r--sql/tztime.cc192
49 files changed, 908 insertions, 465 deletions
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 603e0bf59dc..cd15fa8b20f 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -1488,7 +1488,8 @@ bool ha_partition::is_crashed() const
int ha_partition::prepare_new_partition(TABLE *tbl,
HA_CREATE_INFO *create_info,
handler *file, const char *part_name,
- partition_element *p_elem)
+ partition_element *p_elem,
+ uint disable_non_uniq_indexes)
{
int error;
DBUG_ENTER("prepare_new_partition");
@@ -1531,6 +1532,7 @@ int ha_partition::prepare_new_partition(TABLE *tbl,
m_open_test_lock | HA_OPEN_NO_PSI_CALL)))
goto error_open;
DBUG_PRINT("info", ("partition %s opened", part_name));
+
/*
Note: if you plan to add another call that may return failure,
better to do it before external_lock() as cleanup_new_partition()
@@ -1541,6 +1543,9 @@ int ha_partition::prepare_new_partition(TABLE *tbl,
goto error_external_lock;
DBUG_PRINT("info", ("partition %s external locked", part_name));
+ if (disable_non_uniq_indexes)
+ file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
+
DBUG_RETURN(0);
error_external_lock:
(void) file->ha_close();
@@ -1836,6 +1841,14 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
on them to prepare them for copy phase and also for later close
calls
*/
+
+ /*
+ Before creating new partitions check whether indexes are disabled
+ in the partitions.
+ */
+
+ uint disable_non_uniq_indexes = indexes_are_disabled();
+
i= 0;
part_count= 0;
part_it.rewind();
@@ -1870,11 +1883,13 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
if ((error= prepare_new_partition(table, create_info,
new_file_array[part],
(const char *)part_name_buff,
- sub_elem)))
+ sub_elem,
+ disable_non_uniq_indexes)))
{
cleanup_new_partition(part_count);
DBUG_RETURN(error);
}
+
m_added_file[part_count++]= new_file_array[part];
} while (++j < num_subparts);
}
@@ -1887,11 +1902,13 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
if ((error= prepare_new_partition(table, create_info,
new_file_array[i],
(const char *)part_name_buff,
- part_elem)))
+ part_elem,
+ disable_non_uniq_indexes)))
{
cleanup_new_partition(part_count);
DBUG_RETURN(error);
}
+
m_added_file[part_count++]= new_file_array[i];
}
}
@@ -7870,7 +7887,7 @@ void ha_partition::print_error(int error, myf errflag)
if ((error == HA_ERR_NO_PARTITION_FOUND) &&
! (thd->lex->alter_info.flags & Alter_info::ALTER_TRUNCATE_PARTITION))
- m_part_info->print_no_partition_found(table);
+ m_part_info->print_no_partition_found(table, errflag);
else if (error == HA_ERR_ROW_IN_WRONG_PARTITION)
{
/* Should only happen on DELETE or UPDATE! */
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 71a82b5af6d..05262e750f7 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -343,7 +343,8 @@ private:
void cleanup_new_partition(uint part_count);
int prepare_new_partition(TABLE *table, HA_CREATE_INFO *create_info,
handler *file, const char *part_name,
- partition_element *p_elem);
+ partition_element *p_elem,
+ uint disable_non_uniq_indexes);
/*
delete_table and rename_table uses very similar logic which
is packed into this routine.
diff --git a/sql/handler.cc b/sql/handler.cc
index 0088d6010a5..521723e4049 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1308,7 +1308,10 @@ int ha_commit_trans(THD *thd, bool all)
Free resources and perform other cleanup even for 'empty' transactions.
*/
if (is_real_trans)
+ {
thd->transaction.cleanup();
+ thd->wakeup_subsequent_commits(error);
+ }
DBUG_RETURN(0);
}
@@ -1342,6 +1345,7 @@ int ha_commit_trans(THD *thd, bool all)
thd->variables.lock_wait_timeout))
{
ha_rollback_trans(thd, all);
+ thd->wakeup_subsequent_commits(1);
DBUG_RETURN(1);
}
@@ -1429,6 +1433,7 @@ done:
err:
error= 1; /* Transaction was rolled back */
ha_rollback_trans(thd, all);
+ thd->wakeup_subsequent_commits(error);
end:
if (rw_trans && mdl_request.ticket)
@@ -1474,8 +1479,12 @@ int ha_commit_one_phase(THD *thd, bool all)
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
int res;
DBUG_ENTER("ha_commit_one_phase");
- if (is_real_trans && (res= thd->wait_for_prior_commit()))
- DBUG_RETURN(res);
+ if (is_real_trans)
+ {
+ DEBUG_SYNC(thd, "ha_commit_one_phase");
+ if ((res= thd->wait_for_prior_commit()))
+ DBUG_RETURN(res);
+ }
res= commit_one_phase_2(thd, all, trans, is_real_trans);
DBUG_RETURN(res);
}
@@ -1487,6 +1496,8 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
int error= 0;
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
DBUG_ENTER("commit_one_phase_2");
+ if (is_real_trans)
+ DEBUG_SYNC(thd, "commit_one_phase_2");
if (ha_info)
{
for (; ha_info; ha_info= ha_info_next)
@@ -1599,10 +1610,7 @@ int ha_rollback_trans(THD *thd, bool all)
/* Always cleanup. Even if nht==0. There may be savepoints. */
if (is_real_trans)
- {
- thd->wakeup_subsequent_commits(error);
thd->transaction.cleanup();
- }
if (all)
thd->transaction_rollback_request= FALSE;
@@ -3493,7 +3501,7 @@ void handler::print_error(int error, myf errflag)
}
}
else
- my_error(ER_GET_ERRNO, errflag, error, table_type());
+ my_error(ER_GET_ERRNO, errflag, error, table_type());
DBUG_VOID_RETURN;
}
}
@@ -5564,8 +5572,10 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
"", 0, "DISABLED", 8) ? 1 : 0;
}
else
+ {
result= db_type->show_status &&
db_type->show_status(db_type, thd, stat_print, stat) ? 1 : 0;
+ }
}
/*
diff --git a/sql/item.cc b/sql/item.cc
index 5bc9d5816eb..1295902c1cd 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -4698,6 +4698,12 @@ bool is_outer_table(TABLE_LIST *table, SELECT_LEX *select)
/**
Resolve the name of an outer select column reference.
+ @param[in] thd current thread
+ @param[in,out] from_field found field reference or (Field*)not_found_field
+ @param[in,out] reference view column if this item was resolved to a
+ view column
+
+ @description
The method resolves the column reference represented by 'this' as a column
present in outer selects that contain current select.
@@ -4707,10 +4713,16 @@ bool is_outer_table(TABLE_LIST *table, SELECT_LEX *select)
current select as dependent. The found reference of field should be
provided in 'from_field'.
- @param[in] thd current thread
- @param[in,out] from_field found field reference or (Field*)not_found_field
- @param[in,out] reference view column if this item was resolved to a
- view column
+ The cache is critical for prepared statements of type:
+
+ SELECT a FROM (SELECT a FROM test.t1) AS s1 NATURAL JOIN t2 AS s2;
+
+ This is internally converted to a join similar to
+
+ SELECT a FROM t1 AS s1,t2 AS s2 WHERE t2.a=t1.a;
+
+ Without the cache, we would on re-prepare not know if 'a' did match
+ s1.a or s2.a.
@note
This is the inner loop of Item_field::fix_fields:
@@ -4740,7 +4752,12 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
enum_parsing_place place= NO_MATTER;
bool field_found= (*from_field != not_found_field);
bool upward_lookup= FALSE;
+ TABLE_LIST *table_list;
+ /* Calulate the TABLE_LIST for the table */
+ table_list= (cached_table ? cached_table :
+ field_found && (*from_field) != view_ref_found ?
+ (*from_field)->table->pos_in_table_list : 0);
/*
If there are outer contexts (outer selects, but current select is
not derived table or view) try to resolve this reference in the
@@ -4759,6 +4776,15 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
if (current_sel->master_unit()->first_select()->linkage !=
DERIVED_TABLE_TYPE)
outer_context= context->outer_context;
+
+ /*
+ This assert is to ensure we have an outer contex when *from_field
+ is set.
+ If this would not be the case, we would assert in mark_as_dependent
+ as last_checked_countex == context
+ */
+ DBUG_ASSERT(outer_context || !*from_field ||
+ *from_field == not_found_field);
for (;
outer_context;
outer_context= outer_context->outer_context)
@@ -4775,7 +4801,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
to find_field_in_tables(). Only need to find appropriate context.
*/
if (field_found && outer_context->select_lex !=
- cached_table->select_lex)
+ table_list->select_lex)
continue;
/*
In case of a view, find_field_in_tables() writes the pointer to
@@ -4974,9 +5000,9 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
if (last_checked_context->select_lex->having_fix_field)
{
Item_ref *rf;
- rf= new Item_ref(context,
- (cached_table->db[0] ? cached_table->db : 0),
- (char*) cached_table->alias, (char*) field_name);
+ rf= new Item_ref(context, (*from_field)->table->s->db.str,
+ (*from_field)->table->alias.c_ptr(),
+ (char*) field_name);
if (!rf)
return -1;
thd->change_item_tree(reference, rf);
@@ -5047,6 +5073,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
if (!field) // If field is not checked
{
+ TABLE_LIST *table_list;
/*
In case of view, find_field_in_tables() write pointer to view field
expression to 'reference', i.e. it substitute that expression instead
@@ -5132,11 +5159,14 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
else if (!from_field)
goto error;
- if (!outer_fixed && cached_table && cached_table->select_lex &&
+ table_list= (cached_table ? cached_table :
+ from_field != view_ref_found ?
+ from_field->table->pos_in_table_list : 0);
+ if (!outer_fixed && table_list && table_list->select_lex &&
context->select_lex &&
- cached_table->select_lex != context->select_lex &&
- !context->select_lex->is_merged_child_of(cached_table->select_lex) &&
- is_outer_table(cached_table, context->select_lex))
+ table_list->select_lex != context->select_lex &&
+ !context->select_lex->is_merged_child_of(table_list->select_lex) &&
+ is_outer_table(table_list, context->select_lex))
{
int ret;
if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
diff --git a/sql/item.h b/sql/item.h
index 6afeca66f0a..f0986e3728d 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -332,6 +332,8 @@ struct Name_resolution_context: Sql_alloc
*/
TABLE_LIST *last_name_resolution_table;
+ /* Cache first_name_resolution_table in setup_natural_join_row_types */
+ TABLE_LIST *natural_join_first_table;
/*
SELECT_LEX item belong to, in case of merged VIEW it can differ from
SELECT_LEX where item was created, so we can't use table_list/field_list
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 8858837188d..2ff93b5538a 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2943,11 +2943,6 @@ bool Item_func_min_max::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
}
unpack_time(min_max, ltime);
- if (!(fuzzy_date & TIME_TIME_ONLY) &&
- ((null_value= check_date_with_warn(ltime, fuzzy_date,
- MYSQL_TIMESTAMP_ERROR))))
- return true;
-
if (compare_as_dates->field_type() == MYSQL_TYPE_DATE)
{
ltime->time_type= MYSQL_TIMESTAMP_DATE;
@@ -2958,8 +2953,15 @@ bool Item_func_min_max::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
ltime->time_type= MYSQL_TIMESTAMP_TIME;
ltime->hour+= (ltime->month * 32 + ltime->day) * 24;
ltime->month= ltime->day= 0;
+ if (adjust_time_range_with_warn(ltime,
+ std::min<uint>(decimals, TIME_SECOND_PART_DIGITS)))
+ return (null_value= true);
}
+ if (!(fuzzy_date & TIME_TIME_ONLY) &&
+ ((null_value= check_date_with_warn(ltime, fuzzy_date,
+ MYSQL_TIMESTAMP_ERROR))))
+ return true;
return (null_value= 0);
}
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index fc5dfe0994e..1947dae0c50 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.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
@@ -65,11 +65,6 @@ C_MODE_END
size_t username_char_length= 80;
-/**
- @todo Remove this. It is not safe to use a shared String object.
- */
-String my_empty_string("",default_charset_info);
-
/*
For the Items which have only val_str_ascii() method
and don't have their own "native" val_str(),
@@ -2839,7 +2834,7 @@ String *Item_func_make_set::val_str(String *str)
ulonglong bits;
bool first_found=0;
Item **ptr=args+1;
- String *result=&my_empty_string;
+ String *result= make_empty_result();
bits=args[0]->val_int();
if ((null_value=args[0]->null_value))
@@ -3286,7 +3281,9 @@ String *Item_func_conv::val_str(String *str)
int to_base= (int) args[2]->val_int();
int err;
+ // Note that abs(INT_MIN) is undefined.
if (args[0]->null_value || args[1]->null_value || args[2]->null_value ||
+ from_base == INT_MIN || to_base == INT_MIN ||
abs(to_base) > 36 || abs(to_base) < 2 ||
abs(from_base) > 36 || abs(from_base) < 2 || !(res->length()))
{
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 4b9ec50c164..a33f4910fd5 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -1206,7 +1206,5 @@ public:
String *val_str(String *);
};
-extern String my_empty_string;
-
#endif /* ITEM_STRFUNC_INCLUDED */
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 367ff39eab6..32816551491 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1595,8 +1595,12 @@ void Item_sum_count::clear()
bool Item_sum_count::add()
{
- if (!args[0]->maybe_null || !args[0]->is_null())
- count++;
+ for (uint i=0; i<arg_count; i++)
+ {
+ if (args[i]->maybe_null && args[i]->is_null())
+ return 0;
+ }
+ count++;
return 0;
}
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 6ffa8b2af46..cdbabfae962 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2597,7 +2597,7 @@ bool Item_func_add_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
bool is_time= 0;
long days, microseconds;
longlong seconds;
- int l_sign= sign, was_cut= 0;
+ int l_sign= sign;
if (is_date) // TIMESTAMP function
{
@@ -2648,16 +2648,7 @@ bool Item_func_add_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
}
ltime->hour+= days*24;
-
- MYSQL_TIME copy= *ltime;
- ErrConvTime str(&copy);
-
- check_time_range(ltime, decimals, &was_cut);
- if (was_cut)
- make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
- &str, MYSQL_TIMESTAMP_TIME, NullS);
-
- return (null_value= 0);
+ return (null_value= adjust_time_range_with_warn(ltime, decimals));
}
@@ -2695,7 +2686,7 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
DBUG_ASSERT(fixed == 1);
longlong seconds;
long microseconds;
- int l_sign= 1, was_cut= 0;
+ int l_sign= 1;
MYSQL_TIME l_time1,l_time2,l_time3;
ErrConvTime str(&l_time3);
@@ -2739,12 +2730,7 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
return (null_value= 1);
*ltime= l_time3;
- check_time_range(ltime, decimals, &was_cut);
-
- if (was_cut)
- make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
- &str, MYSQL_TIMESTAMP_TIME, NullS);
- return (null_value= 0);
+ return (null_value= adjust_time_range_with_warn(ltime, decimals));
}
/**
diff --git a/sql/log.cc b/sql/log.cc
index 90305ec227e..f531d301b63 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -6628,16 +6628,17 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd,
to commit. If so, we add those to the queue as well, transitively for all
waiters.
- @retval TRUE If queued as the first entry in the queue (meaning this
- is the leader)
- @retval FALSE Otherwise
+ @retval < 0 Error
+ @retval > 0 If queued as the first entry in the queue (meaning this
+ is the leader)
+ @retval 0 Otherwise (queued as participant, leader handles the commit)
*/
-bool
+int
MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
{
group_commit_entry *entry, *orig_queue;
- wait_for_commit *list, *cur, *last;
+ wait_for_commit *cur, *last;
wait_for_commit *wfc;
DBUG_ENTER("MYSQL_BIN_LOG::queue_for_group_commit");
@@ -6657,6 +6658,7 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
/* Do an extra check here, this time safely under lock. */
if (wfc->waiting_for_commit)
{
+ PSI_stage_info old_stage;
/*
By setting wfc->opaque_pointer to our own entry, we mark that we are
ready to commit, but waiting for another transaction to commit before
@@ -6667,16 +6669,58 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
queued_by_other flag is set.
*/
wfc->opaque_pointer= orig_entry;
+ orig_entry->thd->ENTER_COND(&wfc->COND_wait_commit,
+ &wfc->LOCK_wait_commit,
+ &stage_waiting_for_prior_transaction_to_commit,
+ &old_stage);
DEBUG_SYNC(orig_entry->thd, "group_commit_waiting_for_prior");
- do
- {
+ while (wfc->waiting_for_commit && !orig_entry->thd->check_killed())
mysql_cond_wait(&wfc->COND_wait_commit, &wfc->LOCK_wait_commit);
- } while (wfc->waiting_for_commit);
wfc->opaque_pointer= NULL;
DBUG_PRINT("info", ("After waiting for prior commit, queued_by_other=%d",
orig_entry->queued_by_other));
+
+ if (wfc->waiting_for_commit)
+ {
+ /* Wait terminated due to kill. */
+ wait_for_commit *loc_waitee= wfc->waitee;
+ mysql_mutex_lock(&loc_waitee->LOCK_wait_commit);
+ if (loc_waitee->wakeup_subsequent_commits_running ||
+ orig_entry->queued_by_other)
+ {
+ /* Our waitee is already waking us up, so ignore the kill. */
+ mysql_mutex_unlock(&loc_waitee->LOCK_wait_commit);
+ do
+ {
+ mysql_cond_wait(&wfc->COND_wait_commit, &wfc->LOCK_wait_commit);
+ } while (wfc->waiting_for_commit);
+ }
+ else
+ {
+ /* We were killed, so remove us from the list of waitee. */
+ wfc->remove_from_list(&loc_waitee->subsequent_commits_list);
+ mysql_mutex_unlock(&loc_waitee->LOCK_wait_commit);
+
+ orig_entry->thd->EXIT_COND(&old_stage);
+ /* Interrupted by kill. */
+ DEBUG_SYNC(orig_entry->thd, "group_commit_waiting_for_prior_killed");
+ wfc->wakeup_error= orig_entry->thd->killed_errno();
+ if (wfc->wakeup_error)
+ wfc->wakeup_error= ER_QUERY_INTERRUPTED;
+ my_message(wfc->wakeup_error, ER(wfc->wakeup_error), MYF(0));
+ DBUG_RETURN(-1);
+ }
+ }
+ orig_entry->thd->EXIT_COND(&old_stage);
+ }
+ else
+ mysql_mutex_unlock(&wfc->LOCK_wait_commit);
+
+ if (wfc->wakeup_error)
+ {
+ my_error(ER_PRIOR_COMMIT_FAILED, MYF(0));
+ DBUG_RETURN(-1);
}
- mysql_mutex_unlock(&wfc->LOCK_wait_commit);
}
/*
@@ -6685,7 +6729,7 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
then there is nothing else to do.
*/
if (orig_entry->queued_by_other)
- DBUG_RETURN(false);
+ DBUG_RETURN(0);
/* Now enqueue ourselves in the group commit queue. */
DEBUG_SYNC(orig_entry->thd, "commit_before_enqueue");
@@ -6723,9 +6767,8 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
used by the caller or any other function.
*/
- list= wfc;
- cur= list;
- last= list;
+ cur= wfc;
+ last= wfc;
entry= orig_entry;
for (;;)
{
@@ -6751,11 +6794,11 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
*/
if (cur->subsequent_commits_list)
{
- bool have_lock;
wait_for_commit *waiter;
+ wait_for_commit *wakeup_list= NULL;
+ wait_for_commit **wakeup_next_ptr= &wakeup_list;
mysql_mutex_lock(&cur->LOCK_wait_commit);
- have_lock= true;
/*
Grab the list, now safely under lock, and process it if still
non-empty.
@@ -6796,18 +6839,68 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
For this, we need to set the "wakeup running" flag and release
the waitee lock to avoid a deadlock, see comments on
THD::wakeup_subsequent_commits2() for details.
+
+ So we need to put these on a list and delay the wakeup until we
+ have released the lock.
*/
- if (have_lock)
+ *wakeup_next_ptr= waiter;
+ wakeup_next_ptr= &waiter->next_subsequent_commit;
+ }
+ waiter= next;
+ }
+ if (wakeup_list)
+ {
+ /* Now release our lock and do the wakeups that were delayed above. */
+ cur->wakeup_subsequent_commits_running= true;
+ mysql_mutex_unlock(&cur->LOCK_wait_commit);
+ for (;;)
+ {
+ wait_for_commit *next;
+
+ /*
+ ToDo: We wakeup the waiter here, so that it can have the chance to
+ reach its own commit state and queue up for this same group commit,
+ if it is still pending.
+
+ One problem with this is that if the waiter does not reach its own
+ commit state before this group commit starts, and then the group
+ commit fails (binlog write failure), we do not get to propagate
+ the error to the waiter.
+
+ A solution for this could be to delay the wakeup until commit is
+ successful. But then we need to set a flag in the waitee that it is
+ already queued for group commit, so that the waiter can check this
+ flag and queue itself if it _does_ reach the commit state in time.
+
+ (But error handling in case of binlog write failure is currently
+ broken in other ways, as well).
+ */
+ if (&wakeup_list->next_subsequent_commit == wakeup_next_ptr)
{
- have_lock= false;
- cur->wakeup_subsequent_commits_running= true;
- mysql_mutex_unlock(&cur->LOCK_wait_commit);
+ /* The last one in the list. */
+ wakeup_list->wakeup(0);
+ break;
}
- waiter->wakeup(0);
+ /*
+ Important: don't access wakeup_list->next after the wakeup() call,
+ it may be invalidated by the other thread.
+ */
+ next= wakeup_list->next_subsequent_commit;
+ wakeup_list->wakeup(0);
+ wakeup_list= next;
}
- waiter= next;
+ /*
+ We need a full memory barrier between walking the list and clearing
+ the flag wakeup_subsequent_commits_running. This barrier is needed
+ to ensure that no other thread will start to modify the list
+ pointers before we are done traversing the list.
+
+ But wait_for_commit::wakeup(), which was called above, does a full
+ memory barrier already (it locks a mutex).
+ */
+ cur->wakeup_subsequent_commits_running= false;
}
- if (have_lock)
+ else
mysql_mutex_unlock(&cur->LOCK_wait_commit);
}
if (cur == last)
@@ -6821,29 +6914,6 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
DBUG_ASSERT(entry != NULL);
}
- /*
- Now we need to clear the wakeup_subsequent_commits_running flags.
-
- We need a full memory barrier between walking the list above, and clearing
- the flag wakeup_subsequent_commits_running below. This barrier is needed
- to ensure that no other thread will start to modify the list pointers
- before we are done traversing the list.
-
- But wait_for_commit::wakeup(), which was called above for any other thread
- that might modify the list in parallel, does a full memory barrier already
- (it locks a mutex).
- */
- if (list)
- {
- for (;;)
- {
- list->wakeup_subsequent_commits_running= false;
- if (list == last)
- break;
- list= list->next_subsequent_commit;
- }
- }
-
if (opt_binlog_commit_wait_count > 0)
mysql_cond_signal(&COND_prepare_ordered);
mysql_mutex_unlock(&LOCK_prepare_ordered);
@@ -6857,13 +6927,15 @@ MYSQL_BIN_LOG::queue_for_group_commit(group_commit_entry *orig_entry)
bool
MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry)
{
- bool is_leader= queue_for_group_commit(entry);
+ int is_leader= queue_for_group_commit(entry);
/*
The first in the queue handles group commit for all; the others just wait
to be signalled when group commit is done.
*/
- if (is_leader)
+ if (is_leader < 0)
+ return true; /* Error */
+ else if (is_leader)
trx_group_commit_leader(entry);
else if (!entry->queued_by_other)
entry->thd->wait_for_wakeup_ready();
diff --git a/sql/log.h b/sql/log.h
index 73518d2594f..45381152d97 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -540,7 +540,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
void do_checkpoint_request(ulong binlog_id);
void purge();
int write_transaction_or_stmt(group_commit_entry *entry, uint64 commit_id);
- bool queue_for_group_commit(group_commit_entry *entry);
+ int queue_for_group_commit(group_commit_entry *entry);
bool write_transaction_to_binlog_events(group_commit_entry *entry);
void trx_group_commit_leader(group_commit_entry *leader);
bool is_xidlist_idle_nolock();
diff --git a/sql/log_event.cc b/sql/log_event.cc
index f24e85eff70..0af7a2ed344 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -6988,9 +6988,7 @@ int Intvar_log_event::do_apply_event(rpl_group_info *rgi)
switch (type) {
case LAST_INSERT_ID_EVENT:
- thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1;
- thd->first_successful_insert_id_in_prev_stmt_for_binlog=
- thd->first_successful_insert_id_in_prev_stmt= val;
+ thd->first_successful_insert_id_in_prev_stmt= val;
DBUG_PRINT("info",("last_insert_id_event: %ld", (long) val));
break;
case INSERT_ID_EVENT:
@@ -7255,7 +7253,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
res= trans_commit(thd); /* Automatically rolls back on error. */
thd->mdl_context.release_transactional_locks();
- if (sub_id)
+ if (!res && sub_id)
rpl_global_gtid_slave_state.update_state_hash(sub_id, &gtid);
/*
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 5dbb3407428..984d9cbc968 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3390,7 +3390,6 @@ void my_message_sql(uint error, const char *str, myf MyFlags)
DBUG_ASSERT(str != NULL);
DBUG_ASSERT(error != 0);
- mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_ERROR, error, str);
if (MyFlags & ME_JUST_INFO)
{
level= Sql_condition::WARN_LEVEL_NOTE;
@@ -3413,6 +3412,8 @@ void my_message_sql(uint error, const char *str, myf MyFlags)
thd->is_fatal_error= 1;
(void) thd->raise_condition(error, NULL, level, str);
}
+ else
+ mysql_audit_general(0, MYSQL_AUDIT_GENERAL_ERROR, error, str);
/* When simulating OOM, skip writing to error log to avoid mtr errors */
DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_VOID_RETURN;);
@@ -9414,6 +9415,8 @@ PSI_stage_info stage_binlog_waiting_background_tasks= { 0, "Waiting for backgrou
PSI_stage_info stage_binlog_processing_checkpoint_notify= { 0, "Processing binlog checkpoint notification", 0};
PSI_stage_info stage_binlog_stopping_background_thread= { 0, "Stopping binlog background thread", 0};
PSI_stage_info stage_waiting_for_work_from_sql_thread= { 0, "Waiting for work from SQL thread", 0};
+PSI_stage_info stage_waiting_for_prior_transaction_to_commit= { 0, "Waiting for prior transaction to commit", 0};
+PSI_stage_info stage_waiting_for_room_in_worker_thread= { 0, "Waiting for room in worker thread event queue", 0};
#ifdef HAVE_PSI_INTERFACE
@@ -9421,6 +9424,12 @@ PSI_stage_info *all_server_stages[]=
{
& stage_after_create,
& stage_allocating_local_table,
+ & stage_alter_inplace,
+ & stage_alter_inplace_commit,
+ & stage_alter_inplace_prepare,
+ & stage_binlog_processing_checkpoint_notify,
+ & stage_binlog_stopping_background_thread,
+ & stage_binlog_waiting_background_tasks,
& stage_changing_master,
& stage_checking_master_version,
& stage_checking_permissions,
@@ -9430,9 +9439,9 @@ PSI_stage_info *all_server_stages[]=
& stage_closing_tables,
& stage_connecting_to_master,
& stage_converting_heap_to_myisam,
+ & stage_copy_to_tmp_table,
& stage_copying_to_group_table,
& stage_copying_to_tmp_table,
- & stage_copy_to_tmp_table,
& stage_creating_delayed_handler,
& stage_creating_sort_index,
& stage_creating_table,
@@ -9481,8 +9490,13 @@ PSI_stage_info *all_server_stages[]=
& stage_sending_cached_result_to_client,
& stage_sending_data,
& stage_setup,
- & stage_slave_has_read_all_relay_log,
& stage_show_explain,
+ & stage_slave_has_read_all_relay_log,
+ & stage_slave_waiting_event_from_coordinator,
+ & stage_slave_waiting_worker_queue,
+ & stage_slave_waiting_worker_to_free_events,
+ & stage_slave_waiting_worker_to_release_partition,
+ & stage_slave_waiting_workers_to_exit,
& stage_sorting,
& stage_sorting_for_group,
& stage_sorting_for_order,
@@ -9501,18 +9515,23 @@ PSI_stage_info *all_server_stages[]=
& stage_user_sleep,
& stage_verifying_table,
& stage_waiting_for_delay_list,
+ & stage_waiting_for_gtid_to_be_written_to_binary_log,
& stage_waiting_for_handler_insert,
& stage_waiting_for_handler_lock,
& stage_waiting_for_handler_open,
& stage_waiting_for_insert,
& stage_waiting_for_master_to_send_event,
& stage_waiting_for_master_update,
+ & stage_waiting_for_prior_transaction_to_commit,
+ & stage_waiting_for_query_cache_lock,
+ & stage_waiting_for_relay_log_space,
+ & stage_waiting_for_room_in_worker_thread,
& stage_waiting_for_slave_mutex_on_exit,
& stage_waiting_for_slave_thread_to_start,
& stage_waiting_for_table_flush,
- & stage_waiting_for_query_cache_lock,
& stage_waiting_for_the_next_event_in_relay_log,
& stage_waiting_for_the_slave_thread_to_advance_position,
+ & stage_waiting_for_work_from_sql_thread,
& stage_waiting_to_finalize_termination,
& stage_waiting_to_get_readlock
};
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 12b5d857e6e..1b34c485101 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -432,6 +432,9 @@ extern PSI_stage_info stage_binlog_waiting_background_tasks;
extern PSI_stage_info stage_binlog_processing_checkpoint_notify;
extern PSI_stage_info stage_binlog_stopping_background_thread;
extern PSI_stage_info stage_waiting_for_work_from_sql_thread;
+extern PSI_stage_info stage_waiting_for_prior_transaction_to_commit;
+extern PSI_stage_info stage_waiting_for_room_in_worker_thread;
+
#ifdef HAVE_PSI_STATEMENT_INTERFACE
/**
Statement instrumentation keys (sql).
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index fcb08bfbfc9..b7ee46361ae 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.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, 2014, SkySQL 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
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 6982db898fb..22566ffc7e0 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -10778,15 +10778,16 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
{
KEY *table_key=quick->head->key_info+quick->index;
flag=EQ_RANGE;
- if ((table_key->flags & HA_NOSAME) && key->part == table_key->user_defined_key_parts-1)
+ if ((table_key->flags & HA_NOSAME) &&
+ key_tree->part == table_key->user_defined_key_parts-1)
{
- if (!(table_key->flags & HA_NULL_PART_KEY) ||
- !null_part_in_key(key,
- param->min_key,
- (uint) (tmp_min_key - param->min_key)))
- flag|= UNIQUE_RANGE;
- else
- flag|= NULL_RANGE;
+ if ((table_key->flags & HA_NULL_PART_KEY) &&
+ null_part_in_key(key,
+ param->min_key,
+ (uint) (tmp_min_key - param->min_key)))
+ flag|= NULL_RANGE;
+ else
+ flag|= UNIQUE_RANGE;
}
}
}
@@ -10816,7 +10817,7 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
}
/*
- Return 1 if there is only one range and this uses the whole primary key
+ Return 1 if there is only one range and this uses the whole unique key
*/
bool QUICK_RANGE_SELECT::unique_key_range()
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index a9bff4b37bf..8c38a2d4eb9 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -1529,7 +1529,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
for (tl= (TABLE_LIST*)(parent_lex->table_list.first); tl->next_local; tl= tl->next_local)
{}
- tl->next_local= subq_lex->leaf_tables.head();
+ tl->next_local= subq_lex->join->tables_list;
/* A theory: no need to re-connect the next_global chain */
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 44407bd737f..ca455c0d7bc 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -1852,7 +1852,7 @@ end:
RETURN VALUES
*/
-void partition_info::print_no_partition_found(TABLE *table_arg)
+void partition_info::print_no_partition_found(TABLE *table_arg, myf errflag)
{
char buf[100];
char *buf_ptr= (char*)&buf;
@@ -1866,7 +1866,7 @@ void partition_info::print_no_partition_found(TABLE *table_arg)
SELECT_ACL, &table_list, TRUE))
{
my_message(ER_NO_PARTITION_FOR_GIVEN_VALUE,
- ER(ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT), MYF(0));
+ ER(ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT), errflag);
}
else
{
@@ -1882,7 +1882,7 @@ void partition_info::print_no_partition_found(TABLE *table_arg)
part_expr->unsigned_flag ? 10 : -10);
dbug_tmp_restore_column_map(table_arg->read_set, old_map);
}
- my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf_ptr);
+ my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, errflag, buf_ptr);
}
}
diff --git a/sql/partition_info.h b/sql/partition_info.h
index 777cd6065eb..e5029c385c1 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -317,7 +317,7 @@ public:
bool check_partition_info(THD *thd, handlerton **eng_type,
handler *file, HA_CREATE_INFO *info,
bool check_partition_function);
- void print_no_partition_found(TABLE *table);
+ void print_no_partition_found(TABLE *table, myf errflag);
void print_debug(const char *str, uint*);
Item* get_column_item(Item *item, Field *field);
int fix_partition_values(THD *thd,
diff --git a/sql/records.cc b/sql/records.cc
index e534c04935a..1b230c41156 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -189,7 +189,8 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
info->table=table;
info->forms= &info->table; /* Only one table */
- if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE &&
+ if ((table->s->tmp_table == INTERNAL_TMP_TABLE ||
+ table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE) &&
!table->sort.addon_field)
(void) table->file->extra(HA_EXTRA_MMAP);
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 80125e8aa29..cc65856e37b 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -2,6 +2,7 @@
#include "rpl_parallel.h"
#include "slave.h"
#include "rpl_mi.h"
+#include "debug_sync.h"
/*
@@ -24,7 +25,7 @@ static int
rpt_handle_event(rpl_parallel_thread::queued_event *qev,
struct rpl_parallel_thread *rpt)
{
- int err __attribute__((unused));
+ int err;
rpl_group_info *rgi= qev->rgi;
Relay_log_info *rli= rgi->rli;
THD *thd= rgi->thd;
@@ -142,7 +143,7 @@ finish_event_group(THD *thd, int err, uint64 sub_id,
if (err)
wfc->unregister_wait_for_prior_commit();
else
- wfc->wait_for_prior_commit();
+ err= wfc->wait_for_prior_commit(thd);
thd->wait_for_commit_ptr= NULL;
/*
@@ -172,6 +173,18 @@ finish_event_group(THD *thd, int err, uint64 sub_id,
}
+static void
+signal_error_to_sql_driver_thread(THD *thd, rpl_group_info *rgi)
+{
+ rgi->is_error= true;
+ rgi->cleanup_context(thd, true);
+ rgi->rli->abort_slave= true;
+ mysql_mutex_lock(rgi->rli->relay_log.get_log_lock());
+ mysql_mutex_unlock(rgi->rli->relay_log.get_log_lock());
+ rgi->rli->relay_log.signal_update();
+}
+
+
pthread_handler_t
handle_rpl_parallel_thread(void *arg)
{
@@ -207,6 +220,7 @@ handle_rpl_parallel_thread(void *arg)
thd->variables.log_slow_filter= global_system_variables.log_slow_filter;
set_slave_thread_options(thd);
thd->client_capabilities = CLIENT_LOCAL_FILES;
+ thd->net.reading_or_writing= 0;
thd_proc_info(thd, "Waiting for work from main SQL threads");
thd->set_time();
thd->variables.lock_wait_timeout= LONG_TIMEOUT;
@@ -284,21 +298,42 @@ handle_rpl_parallel_thread(void *arg)
wait_start_sub_id= rgi->wait_start_sub_id;
if (wait_for_sub_id || wait_start_sub_id)
{
+ bool did_enter_cond= false;
+ PSI_stage_info old_stage;
+
mysql_mutex_lock(&entry->LOCK_parallel_entry);
if (wait_start_sub_id)
{
- while (wait_start_sub_id > entry->last_committed_sub_id)
+ thd->ENTER_COND(&entry->COND_parallel_entry,
+ &entry->LOCK_parallel_entry,
+ &stage_waiting_for_prior_transaction_to_commit,
+ &old_stage);
+ did_enter_cond= true;
+ DEBUG_SYNC(thd, "rpl_parallel_start_waiting_for_prior");
+ while (wait_start_sub_id > entry->last_committed_sub_id &&
+ !thd->check_killed())
mysql_cond_wait(&entry->COND_parallel_entry,
&entry->LOCK_parallel_entry);
+ if (wait_start_sub_id > entry->last_committed_sub_id)
+ {
+ /* The thread got a kill signal. */
+ DEBUG_SYNC(thd, "rpl_parallel_start_waiting_for_prior_killed");
+ thd->send_kill_message();
+ slave_output_error_info(rgi->rli, thd);
+ signal_error_to_sql_driver_thread(thd, rgi);
+ }
+ rgi->wait_start_sub_id= 0; /* No need to check again. */
}
- rgi->wait_start_sub_id= 0; /* No need to check again. */
if (wait_for_sub_id > entry->last_committed_sub_id)
{
wait_for_commit *waitee=
&rgi->wait_commit_group_info->commit_orderer;
rgi->commit_orderer.register_wait_for_prior_commit(waitee);
}
- mysql_mutex_unlock(&entry->LOCK_parallel_entry);
+ if (did_enter_cond)
+ thd->EXIT_COND(&old_stage);
+ else
+ mysql_mutex_unlock(&entry->LOCK_parallel_entry);
}
if(thd->wait_for_commit_ptr)
@@ -341,10 +376,8 @@ handle_rpl_parallel_thread(void *arg)
if (err)
{
- rgi->is_error= true;
slave_output_error_info(rgi->rli, thd);
- rgi->cleanup_context(thd, true);
- rgi->rli->abort_slave= true;
+ signal_error_to_sql_driver_thread(thd, rgi);
}
if (end_of_group)
{
@@ -353,6 +386,7 @@ handle_rpl_parallel_thread(void *arg)
&rgi->commit_orderer);
delete rgi;
group_rgi= rgi= NULL;
+ DEBUG_SYNC(thd, "rpl_parallel_end_of_group");
}
events= next;
@@ -383,11 +417,9 @@ handle_rpl_parallel_thread(void *arg)
half-processed event group.
*/
mysql_mutex_unlock(&rpt->LOCK_rpl_thread);
- group_rgi->is_error= true;
finish_event_group(thd, 1, group_rgi->gtid_sub_id,
group_rgi->parallel_entry, &group_rgi->commit_orderer);
- group_rgi->cleanup_context(thd, true);
- group_rgi->rli->abort_slave= true;
+ signal_error_to_sql_driver_thread(thd, group_rgi);
in_event_group= false;
delete group_rgi;
group_rgi= NULL;
@@ -752,6 +784,8 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
Relay_log_info *rli= serial_rgi->rli;
enum Log_event_type typ;
bool is_group_event;
+ bool did_enter_cond= false;
+ PSI_stage_info old_stage;
/* ToDo: what to do with this lock?!? */
mysql_mutex_unlock(&rli->data_lock);
@@ -766,6 +800,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
sql_thread_stopping= true;
if (sql_thread_stopping)
{
+ delete ev;
/* QQ: Need a better comment why we return false here */
return false;
}
@@ -774,6 +809,7 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
MYF(0))))
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ delete ev;
return true;
}
qev->ev= ev;
@@ -796,6 +832,8 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
{
my_error(ER_OUT_OF_RESOURCES, MYF(MY_WME));
delete rgi;
+ my_free(qev);
+ delete ev;
return true;
}
rgi->is_parallel_exec = true;
@@ -813,6 +851,10 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
However, the commit of this event must wait for the commit of the prior
event, to preserve binlog commit order and visibility across all
servers in the replication hierarchy.
+
+ In addition, we must not start executing this event until we have
+ finished the previous collection of event groups that group-committed
+ together; we use rgi->wait_start_sub_id to control this.
*/
rpl_parallel_thread *rpt= global_rpl_thread_pool.get_thread(e);
rgi->wait_commit_sub_id= e->current_sub_id;
@@ -859,6 +901,21 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
}
else if (cur_thread->queued_size <= opt_slave_parallel_max_queued)
break; // The thread is ready to queue into
+ else if (rli->sql_driver_thd->check_killed())
+ {
+ mysql_mutex_unlock(&cur_thread->LOCK_rpl_thread);
+ my_error(ER_CONNECTION_KILLED, MYF(0));
+ delete rgi;
+ my_free(qev);
+ delete ev;
+ DBUG_EXECUTE_IF("rpl_parallel_wait_queue_max",
+ {
+ debug_sync_set_action(rli->sql_driver_thd,
+ STRING_WITH_LEN("now SIGNAL wait_queue_killed"));
+ };);
+ slave_output_error_info(rli, rli->sql_driver_thd);
+ return true;
+ }
else
{
/*
@@ -866,6 +923,18 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
use for queuing events, so wait for the thread to consume some
of its queue.
*/
+ if (!did_enter_cond)
+ {
+ rli->sql_driver_thd->ENTER_COND(&cur_thread->COND_rpl_thread,
+ &cur_thread->LOCK_rpl_thread,
+ &stage_waiting_for_room_in_worker_thread, &old_stage);
+ did_enter_cond= true;
+ DBUG_EXECUTE_IF("rpl_parallel_wait_queue_max",
+ {
+ debug_sync_set_action(rli->sql_driver_thd,
+ STRING_WITH_LEN("now SIGNAL wait_queue_ready"));
+ };);
+ }
mysql_cond_wait(&cur_thread->COND_rpl_thread,
&cur_thread->LOCK_rpl_thread);
}
@@ -1015,7 +1084,10 @@ rpl_parallel::do_event(rpl_group_info *serial_rgi, Log_event *ev,
*/
rli->event_relay_log_pos= rli->future_event_relay_log_pos;
cur_thread->enqueue(qev);
- mysql_mutex_unlock(&cur_thread->LOCK_rpl_thread);
+ if (did_enter_cond)
+ rli->sql_driver_thd->EXIT_COND(&old_stage);
+ else
+ mysql_mutex_unlock(&cur_thread->LOCK_rpl_thread);
mysql_cond_signal(&cur_thread->COND_rpl_thread);
return false;
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 9036f810020..ac93f9640e8 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -886,11 +886,11 @@ void Relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
int cmp= strcmp(group_relay_log_name, event_relay_log_name);
if (cmp < 0)
{
- group_relay_log_pos= event_relay_log_pos;
+ group_relay_log_pos= rgi->future_event_relay_log_pos;
strmake_buf(group_relay_log_name, event_relay_log_name);
notify_group_relay_log_name_update();
- } else if (cmp == 0 && group_relay_log_pos < event_relay_log_pos)
- group_relay_log_pos= event_relay_log_pos;
+ } else if (cmp == 0 && group_relay_log_pos < rgi->future_event_relay_log_pos)
+ group_relay_log_pos= rgi->future_event_relay_log_pos;
/*
In the parallel case we need to update the master_log_name here, rather
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 4d218bcc35b..617ce2298b1 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -212,7 +212,6 @@ uchar *sys_var::global_value_ptr(THD *thd, LEX_STRING *base)
bool sys_var::check(THD *thd, set_var *var)
{
- do_deprecated_warning(thd);
if ((var->value && do_check(thd, var))
|| (on_check && on_check(this, thd, var)))
{
@@ -546,10 +545,10 @@ int mysql_del_sys_var_chain(sys_var *first)
{
int result= 0;
- /* A write lock should be held on LOCK_system_variables_hash */
-
+ mysql_rwlock_wrlock(&LOCK_system_variables_hash);
for (sys_var *var= first; var; var= var->next)
result|= my_hash_delete(&system_variable_hash, (uchar*) var);
+ mysql_rwlock_unlock(&LOCK_system_variables_hash);
return result;
}
@@ -697,6 +696,7 @@ err:
int set_var::check(THD *thd)
{
+ var->do_deprecated_warning(thd);
if (var->is_readonly())
{
my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), var->name.str, "read only");
diff --git a/sql/set_var.h b/sql/set_var.h
index 318bc04e16e..a6c3b9daccd 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -145,6 +145,7 @@ public:
return (option.id != -1) && ((flags & PARSE_EARLY) == parse_flags) &&
insert_dynamic(array, (uchar*)&option);
}
+ void do_deprecated_warning(THD *thd);
private:
virtual bool do_check(THD *thd, set_var *var) = 0;
@@ -158,7 +159,7 @@ private:
virtual void global_save_default(THD *thd, set_var *var) = 0;
virtual bool session_update(THD *thd, set_var *var) = 0;
virtual bool global_update(THD *thd, set_var *var) = 0;
- void do_deprecated_warning(THD *thd);
+
protected:
/**
A pointer to a value of the variable for SHOW.
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 8da5b3a5c12..25017cef42c 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -1732,30 +1732,8 @@ ER_WRONG_AUTO_KEY 42000 S1009
spa "Puede ser solamente un campo automatico y este debe ser definido como una clave"
swe "Det får finnas endast ett AUTO_INCREMENT-fält och detta måste vara en nyckel"
ukr "Невірне визначення таблиці; Може бути лише один автоматичний стовбець, що повинен бути визначений як ключ"
-ER_READY
- cze "%s: připraven na spojení\nVersion: '%s' socket: '%s' port: %d""
- dan "%s: klar til tilslutninger\nVersion: '%s' socket: '%s' port: %d""
- nla "%s: klaar voor verbindingen\nVersion: '%s' socket: '%s' port: %d""
- eng "%s: ready for connections.\nVersion: '%s' socket: '%s' port: %d"
- est "%s: ootab ühendusi\nVersion: '%s' socket: '%s' port: %d""
- fre "%s: Prêt pour des connexions\nVersion: '%s' socket: '%s' port: %d""
- ger "%s: Bereit für Verbindungen.\nVersion: '%s' Socket: '%s' Port: %d"
- greek "%s: σε αναμονή συνδέσεων\nVersion: '%s' socket: '%s' port: %d""
- hun "%s: kapcsolatra kesz\nVersion: '%s' socket: '%s' port: %d""
- ita "%s: Pronto per le connessioni\nVersion: '%s' socket: '%s' port: %d""
- jpn "%s: 接続準備完了。\nバージョン: '%s' socket: '%s' port: %d""
- kor "%s: 연결 준비중입니다\nVersion: '%s' socket: '%s' port: %d""
- nor "%s: klar for tilkoblinger\nVersion: '%s' socket: '%s' port: %d""
- norwegian-ny "%s: klar for tilkoblingar\nVersion: '%s' socket: '%s' port: %d""
- pol "%s: gotowe do poł?czenia\nVersion: '%s' socket: '%s' port: %d""
- por "%s: Pronto para conexões\nVersion: '%s' socket: '%s' port: %d""
- rum "%s: sint gata pentru conectii\nVersion: '%s' socket: '%s' port: %d""
- rus "%s: Готов принимать соединения.\nВерсия: '%s' сокет: '%s' порт: %d"
- serbian "%s: Spreman za konekcije\nVersion: '%s' socket: '%s' port: %d""
- slo "%s: pripravený na spojenie\nVersion: '%s' socket: '%s' port: %d""
- spa "%s: preparado para conexiones\nVersion: '%s' socket: '%s' port: %d""
- swe "%s: klar att ta emot klienter\nVersion: '%s' socket: '%s' port: %d""
- ukr "%s: Готовий для з'єднань!\nVersion: '%s' socket: '%s' port: %d""
+ER_UNUSED_9
+ eng "You should never see it"
ER_NORMAL_SHUTDOWN
cze "%s: normální ukončení\n"
dan "%s: Normal nedlukning\n"
@@ -5055,19 +5033,19 @@ ER_UNSUPPORTED_PS
eng "This command is not supported in the prepared statement protocol yet"
ger "Dieser Befehl wird im Protokoll für vorbereitete Anweisungen noch nicht unterstützt"
ER_GET_ERRMSG
- dan "Modtog fejl %d '%-.100s' fra %s"
- eng "Got error %d '%-.100s' from %s"
- ger "Fehler %d '%-.100s' von %s"
- jpn "エラー %d '%-.100s' が %s から返されました。"
- nor "Mottok feil %d '%-.100s' fa %s"
- norwegian-ny "Mottok feil %d '%-.100s' fra %s"
+ dan "Modtog fejl %d '%-.200s' fra %s"
+ eng "Got error %d '%-.200s' from %s"
+ ger "Fehler %d '%-.200s' von %s"
+ jpn "エラー %d '%-.200s' が %s から返されました。"
+ nor "Mottok feil %d '%-.200s' fa %s"
+ norwegian-ny "Mottok feil %d '%-.200s' fra %s"
ER_GET_TEMPORARY_ERRMSG
- dan "Modtog temporary fejl %d '%-.100s' fra %s"
- eng "Got temporary error %d '%-.100s' from %s"
- jpn "一時エラー %d '%-.100s' が %s から返されました。"
- ger "Temporärer Fehler %d '%-.100s' von %s"
- nor "Mottok temporary feil %d '%-.100s' fra %s"
- norwegian-ny "Mottok temporary feil %d '%-.100s' fra %s"
+ dan "Modtog temporary fejl %d '%-.200s' fra %s"
+ eng "Got temporary error %d '%-.200s' from %s"
+ jpn "一時エラー %d '%-.200s' が %s から返されました。"
+ ger "Temporärer Fehler %d '%-.200s' von %s"
+ nor "Mottok temporary feil %d '%-.200s' fra %s"
+ norwegian-ny "Mottok temporary feil %d '%-.200s' fra %s"
ER_UNKNOWN_TIME_ZONE
eng "Unknown or incorrect time zone: '%-.64s'"
ger "Unbekannte oder falsche Zeitzone: '%-.64s'"
diff --git a/sql/slave.cc b/sql/slave.cc
index 835b0d9b15a..6854d2bd6de 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1794,10 +1794,14 @@ when it try to get the value of TIME_ZONE global variable from master.";
if (mysql_errno(mysql) == ER_UNKNOWN_SYSTEM_VARIABLE)
{
- // this is tolerable as OM -> NS is supported
- mi->report(WARNING_LEVEL, mysql_errno(mysql),
- "Notifying master by %s failed with "
- "error: %s", query, mysql_error(mysql));
+ /* Ignore this expected error if not a high error level */
+ if (global_system_variables.log_warnings > 1)
+ {
+ // this is tolerable as OM -> NS is supported
+ mi->report(WARNING_LEVEL, mysql_errno(mysql),
+ "Notifying master by %s failed with "
+ "error: %s", query, mysql_error(mysql));
+ }
}
else
{
@@ -6200,6 +6204,17 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size)
}
/*
+ We have to check sql_slave_killed() here an extra time.
+ Otherwise we may miss a wakeup, since last check was done
+ without holding LOCK_log.
+ */
+ if (sql_slave_killed(rgi))
+ {
+ mysql_mutex_unlock(log_lock);
+ break;
+ }
+
+ /*
We can, and should release data_lock while we are waiting for
update. If we do not, show slave status will block
*/
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index a297e18ab47..d9155b38066 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -163,10 +163,11 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
- Run a normal repair using the new index file and the old data file
*/
- if (table->s->frm_version != FRM_VER_TRUE_VARCHAR)
+ if (table->s->frm_version != FRM_VER_TRUE_VARCHAR &&
+ table->s->varchar_fields)
{
error= send_check_errmsg(thd, table_list, "repair",
- "Failed repairing incompatible .frm file");
+ "Failed repairing a very old .frm file as the data file format has changed between versions. Please dump the table in your old system with mysqldump and read it into this system with mysql or mysqlimport");
goto end;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index e3ce2adf862..44d68f35ab2 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2494,6 +2494,7 @@ retry_share:
err_lock:
tdc_release_share(share);
+ DBUG_PRINT("exit", ("failed"));
DBUG_RETURN(TRUE);
}
@@ -6456,7 +6457,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
*/
if (db)
return cur_field;
-
+
if (found)
{
if (report_error == REPORT_ALL_ERRORS ||
@@ -6471,7 +6472,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
if (found)
return found;
-
+
/*
If the field was qualified and there were no tables to search, issue
an error that an unknown table was given. The situation is detected
@@ -7398,10 +7399,16 @@ err:
order, thus when we iterate over it, we are moving from the right
to the left in the FROM clause.
+ NOTES
+ We can't run this many times as the first_name_resolution_table would
+ be different for subsequent runs when sub queries has been optimized
+ away.
+
RETURN
TRUE Error
FALSE OK
*/
+
static bool setup_natural_join_row_types(THD *thd,
List<TABLE_LIST> *from_clause,
Name_resolution_context *context)
@@ -7411,6 +7418,19 @@ static bool setup_natural_join_row_types(THD *thd,
if (from_clause->elements == 0)
DBUG_RETURN(false); /* We come here in the case of UNIONs. */
+ /*
+ Do not redo work if already done:
+ 1) for stored procedures,
+ 2) for multitable update after lock failure and table reopening.
+ */
+ if (!context->select_lex->first_natural_join_processing)
+ {
+ context->first_name_resolution_table= context->natural_join_first_table;
+ DBUG_PRINT("info", ("using cached setup_natural_join_row_types"));
+ DBUG_RETURN(false);
+ }
+ context->select_lex->first_natural_join_processing= false;
+
List_iterator_fast<TABLE_LIST> table_ref_it(*from_clause);
TABLE_LIST *table_ref; /* Current table reference. */
/* Table reference to the left of the current. */
@@ -7427,22 +7447,15 @@ static bool setup_natural_join_row_types(THD *thd,
left_neighbor= table_ref_it++;
}
while (left_neighbor && left_neighbor->sj_subq_pred);
- /*
- Do not redo work if already done:
- 1) for stored procedures,
- 2) for multitable update after lock failure and table reopening.
- */
- if (context->select_lex->first_natural_join_processing)
+
+ if (store_top_level_join_columns(thd, table_ref,
+ left_neighbor, right_neighbor))
+ DBUG_RETURN(true);
+ if (left_neighbor)
{
- if (store_top_level_join_columns(thd, table_ref,
- left_neighbor, right_neighbor))
- DBUG_RETURN(true);
- if (left_neighbor)
- {
- TABLE_LIST *first_leaf_on_the_right;
- first_leaf_on_the_right= table_ref->first_leaf_for_name_resolution();
- left_neighbor->next_name_resolution_table= first_leaf_on_the_right;
- }
+ TABLE_LIST *first_leaf_on_the_right;
+ first_leaf_on_the_right= table_ref->first_leaf_for_name_resolution();
+ left_neighbor->next_name_resolution_table= first_leaf_on_the_right;
}
right_neighbor= table_ref;
}
@@ -7456,8 +7469,11 @@ static bool setup_natural_join_row_types(THD *thd,
DBUG_ASSERT(right_neighbor);
context->first_name_resolution_table=
right_neighbor->first_leaf_for_name_resolution();
- context->select_lex->first_natural_join_processing= false;
-
+ /*
+ This is only to ensure that first_name_resolution_table doesn't
+ change on re-execution
+ */
+ context->natural_join_first_table= context->first_name_resolution_table;
DBUG_RETURN (false);
}
@@ -7803,12 +7819,9 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
if (table_list->merge_underlying_list)
{
DBUG_ASSERT(table_list->is_merged_derived());
- Query_arena *arena= thd->stmt_arena, backup;
+ Query_arena *arena, backup;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
bool res;
- if (arena->is_conventional())
- arena= 0; // For easier test
- else
- thd->set_n_backup_active_arena(arena, &backup);
res= table_list->setup_underlying(thd);
if (arena)
thd->restore_active_arena(arena, &backup);
@@ -8059,7 +8072,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if (!(item= field_iterator.create_item(thd)))
DBUG_RETURN(TRUE);
-// DBUG_ASSERT(item->fixed);
+
/* cache the table for the Item_fields inserted by expanding stars */
if (item->type() == Item::FIELD_ITEM && tables->cacheable_table)
((Item_field *)item)->cached_table= tables;
@@ -8187,11 +8200,8 @@ void wrap_ident(THD *thd, Item **conds)
{
Item_direct_ref_to_ident *wrapper;
DBUG_ASSERT((*conds)->type() == Item::FIELD_ITEM || (*conds)->type() == Item::REF_ITEM);
- Query_arena *arena= thd->stmt_arena, backup;
- if (arena->is_conventional())
- arena= 0;
- else
- thd->set_n_backup_active_arena(arena, &backup);
+ Query_arena *arena, backup;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
if ((wrapper= new Item_direct_ref_to_ident((Item_ident *)(*conds))))
(*conds)= (Item*) wrapper;
if (arena)
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 541318c93a8..bcaea00b081 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1239,6 +1239,7 @@ Sql_condition* THD::raise_condition(uint sql_errno,
got_warning= 1;
break;
case Sql_condition::WARN_LEVEL_ERROR:
+ mysql_audit_general(this, MYSQL_AUDIT_GENERAL_ERROR, sql_errno, msg);
break;
default:
DBUG_ASSERT(FALSE);
@@ -2461,6 +2462,7 @@ bool select_result::check_simple_select() const
static String default_line_term("\n",default_charset_info);
static String default_escaped("\\",default_charset_info);
static String default_field_term("\t",default_charset_info);
+static String default_enclosed_and_line_start("", default_charset_info);
static String default_xml_row_term("<row>", default_charset_info);
sql_exchange::sql_exchange(char *name, bool flag,
@@ -2469,7 +2471,7 @@ sql_exchange::sql_exchange(char *name, bool flag,
{
filetype= filetype_arg;
field_term= &default_field_term;
- enclosed= line_start= &my_empty_string;
+ enclosed= line_start= &default_enclosed_and_line_start;
line_term= filetype == FILETYPE_CSV ?
&default_line_term : &default_xml_row_term;
escaped= &default_escaped;
@@ -6202,12 +6204,54 @@ wait_for_commit::register_wait_for_prior_commit(wait_for_commit *waitee)
returns immediately.
*/
int
-wait_for_commit::wait_for_prior_commit2()
+wait_for_commit::wait_for_prior_commit2(THD *thd)
{
+ PSI_stage_info old_stage;
+ wait_for_commit *loc_waitee;
+
mysql_mutex_lock(&LOCK_wait_commit);
- while (waiting_for_commit)
+ DEBUG_SYNC(thd, "wait_for_prior_commit_waiting");
+ thd->ENTER_COND(&COND_wait_commit, &LOCK_wait_commit,
+ &stage_waiting_for_prior_transaction_to_commit,
+ &old_stage);
+ while (waiting_for_commit && !thd->check_killed())
mysql_cond_wait(&COND_wait_commit, &LOCK_wait_commit);
- mysql_mutex_unlock(&LOCK_wait_commit);
+ if (!waiting_for_commit)
+ {
+ if (wakeup_error)
+ my_error(ER_PRIOR_COMMIT_FAILED, MYF(0));
+ goto end;
+ }
+ /*
+ Wait was interrupted by kill. We need to unregister our wait and give the
+ error. But if a wakeup is already in progress, then we must ignore the
+ kill and not give error, otherwise we get inconsistency between waitee and
+ waiter as to whether we succeed or fail (eg. we may roll back but waitee
+ might attempt to commit both us and any subsequent commits waiting for us).
+ */
+ loc_waitee= this->waitee;
+ mysql_mutex_lock(&loc_waitee->LOCK_wait_commit);
+ if (loc_waitee->wakeup_subsequent_commits_running)
+ {
+ /* We are being woken up; ignore the kill and just wait. */
+ mysql_mutex_unlock(&loc_waitee->LOCK_wait_commit);
+ do
+ {
+ mysql_cond_wait(&COND_wait_commit, &LOCK_wait_commit);
+ } while (waiting_for_commit);
+ goto end;
+ }
+ remove_from_list(&loc_waitee->subsequent_commits_list);
+ mysql_mutex_unlock(&loc_waitee->LOCK_wait_commit);
+
+ DEBUG_SYNC(thd, "wait_for_prior_commit_killed");
+ wakeup_error= thd->killed_errno();
+ if (!wakeup_error)
+ wakeup_error= ER_QUERY_INTERRUPTED;
+ my_message(wakeup_error, ER(wakeup_error), MYF(0));
+
+end:
+ thd->EXIT_COND(&old_stage);
waitee= NULL;
return wakeup_error;
}
@@ -6295,7 +6339,6 @@ wait_for_commit::unregister_wait_for_prior_commit2()
if (waiting_for_commit)
{
wait_for_commit *loc_waitee= this->waitee;
- wait_for_commit **next_ptr_ptr, *cur;
mysql_mutex_lock(&loc_waitee->LOCK_wait_commit);
if (loc_waitee->wakeup_subsequent_commits_running)
{
@@ -6313,17 +6356,7 @@ wait_for_commit::unregister_wait_for_prior_commit2()
else
{
/* Remove ourselves from the list in the waitee. */
- next_ptr_ptr= &loc_waitee->subsequent_commits_list;
- while ((cur= *next_ptr_ptr) != NULL)
- {
- if (cur == this)
- {
- *next_ptr_ptr= this->next_subsequent_commit;
- break;
- }
- next_ptr_ptr= &cur->next_subsequent_commit;
- }
- waiting_for_commit= false;
+ remove_from_list(&loc_waitee->subsequent_commits_list);
mysql_mutex_unlock(&loc_waitee->LOCK_wait_commit);
}
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 19c1ac8f4b6..5c0684f5d68 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -119,6 +119,10 @@ enum enum_filetype { FILETYPE_CSV, FILETYPE_XML };
#define MODE_NO_ENGINE_SUBSTITUTION (1ULL << 30)
#define MODE_PAD_CHAR_TO_FULL_LENGTH (1ULL << 31)
+/* Bits for different old style modes */
+#define OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE 1
+#define OLD_MODE_NO_PROGRESS_INFO 2
+
extern char internal_table_name[2];
extern char empty_c_string[1];
extern LEX_STRING EMPTY_STR;
@@ -498,6 +502,7 @@ typedef struct system_variables
ulonglong long_query_time;
ulonglong optimizer_switch;
sql_mode_t sql_mode; ///< which non-standard SQL behaviour should be enabled
+ sql_mode_t old_behavior; ///< which old SQL behaviour should be enabled
ulonglong option_bits; ///< OPTION_xxx constants, e.g. OPTION_PROFILING
ulonglong join_buff_space_limit;
ulonglong log_slow_filter;
@@ -1681,14 +1686,14 @@ struct wait_for_commit
bool wakeup_subsequent_commits_running;
void register_wait_for_prior_commit(wait_for_commit *waitee);
- int wait_for_prior_commit()
+ int wait_for_prior_commit(THD *thd)
{
/*
Quick inline check, to avoid function call and locking in the common case
where no wakeup is registered, or a registered wait was already signalled.
*/
if (waiting_for_commit)
- return wait_for_prior_commit2();
+ return wait_for_prior_commit2(thd);
else
return wakeup_error;
}
@@ -1714,10 +1719,29 @@ struct wait_for_commit
if (waiting_for_commit)
unregister_wait_for_prior_commit2();
}
+ /*
+ Remove a waiter from the list in the waitee. Used to unregister a wait.
+ The caller must be holding the locks of both waiter and waitee.
+ */
+ void remove_from_list(wait_for_commit **next_ptr_ptr)
+ {
+ wait_for_commit *cur;
+
+ while ((cur= *next_ptr_ptr) != NULL)
+ {
+ if (cur == this)
+ {
+ *next_ptr_ptr= this->next_subsequent_commit;
+ break;
+ }
+ next_ptr_ptr= &cur->next_subsequent_commit;
+ }
+ waiting_for_commit= false;
+ }
void wakeup(int wakeup_error);
- int wait_for_prior_commit2();
+ int wait_for_prior_commit2(THD *thd);
void wakeup_subsequent_commits2(int wakeup_error);
void unregister_wait_for_prior_commit2();
@@ -3571,12 +3595,7 @@ public:
int wait_for_prior_commit()
{
if (wait_for_commit_ptr)
- {
- int err= wait_for_commit_ptr->wait_for_prior_commit();
- if (err)
- my_error(ER_PRIOR_COMMIT_FAILED, MYF(0));
- return err;
- }
+ return wait_for_commit_ptr->wait_for_prior_commit(this);
return 0;
}
void wakeup_subsequent_commits(int wakeup_error)
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 712b1606c11..ebd06a66f60 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -358,6 +358,14 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
if (derived->merged)
return FALSE;
+ if (dt_select->uncacheable & UNCACHEABLE_RAND)
+ {
+ /* There is random function => fall back to materialization. */
+ derived->change_refs_to_fields();
+ derived->set_materialized_derived();
+ return FALSE;
+ }
+
if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
thd->lex->sql_command == SQLCOM_DELETE_MULTI)
thd->save_prep_leaf_list= TRUE;
@@ -604,11 +612,8 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
thd->lex->sql_command == SQLCOM_DELETE_MULTI))))
DBUG_RETURN(FALSE);
- Query_arena *arena= thd->stmt_arena, backup;
- if (arena->is_conventional())
- arena= 0; // For easier test
- else
- thd->set_n_backup_active_arena(arena, &backup);
+ Query_arena *arena, backup;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
SELECT_LEX *first_select= unit->first_select();
@@ -708,7 +713,7 @@ exit:
{
TABLE *table= derived->table;
table->derived_select_number= first_select->select_number;
- table->s->tmp_table= NON_TRANSACTIONAL_TMP_TABLE;
+ table->s->tmp_table= INTERNAL_TMP_TABLE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (derived->referencing_view)
table->grant= derived->grant;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index b764263265e..e0ecfcac72e 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1749,7 +1749,9 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
if (info->ignore &&
!table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
{
- table->file->print_error(error, MYF(ME_JUST_WARNING));
+ if (!(thd->variables.old_behavior &
+ OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE))
+ table->file->print_error(error, MYF(ME_JUST_WARNING));
goto ok_or_after_trg_err;
}
goto err;
@@ -1877,7 +1879,9 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
if (!info->ignore ||
table->file->is_fatal_error(error, HA_CHECK_DUP))
goto err;
- table->file->print_error(error, MYF(ME_JUST_WARNING));
+ if (!(thd->variables.old_behavior &
+ OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE))
+ table->file->print_error(error, MYF(ME_JUST_WARNING));
table->file->restore_auto_increment(prev_insert_id);
goto ok_or_after_trg_err;
}
@@ -2428,6 +2432,10 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
goto error;
dfield_ptr= copy->default_field;
}
+
+ /* Ensure we don't use the table list of the original table */
+ copy->pos_in_table_list= 0;
+
/*
Make a copy of all fields.
The copied fields need to point into the copied record. This is done
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 96dce0acf2a..7096c886281 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -497,13 +497,13 @@ void lex_start(THD *thd)
lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc;
lex->select_lex.group_list.empty();
lex->select_lex.order_list.empty();
+ lex->select_lex.gorder_list.empty();
lex->m_sql_cmd= NULL;
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
lex->spname= NULL;
lex->sphead= NULL;
lex->spcont= NULL;
- lex->m_sql_cmd= NULL;
lex->proc_list.first= 0;
lex->escape_used= FALSE;
lex->query_tables= 0;
@@ -2109,14 +2109,15 @@ void st_select_lex_unit::exclude_tree()
this to 'last' as dependent
SYNOPSIS
- last - pointer to last st_select_lex struct, before wich all
+ last - pointer to last st_select_lex struct, before which all
st_select_lex have to be marked as dependent
NOTE
'last' should be reachable from this st_select_lex_node
*/
-bool st_select_lex::mark_as_dependent(THD *thd, st_select_lex *last, Item *dependency)
+bool st_select_lex::mark_as_dependent(THD *thd, st_select_lex *last,
+ Item *dependency)
{
DBUG_ASSERT(this != last);
@@ -2309,7 +2310,10 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
If we need a bigger array, we must allocate a new one.
*/
if (ref_pointer_array_size >= n_elems)
+ {
+ DBUG_PRINT("info", ("reusing old ref_array"));
return false;
+ }
}
ref_pointer_array= static_cast<Item**>(arena->alloc(sizeof(Item*) * n_elems));
if (ref_pointer_array != NULL)
@@ -2575,7 +2579,9 @@ bool LEX::can_be_merged()
// TODO: do not forget implement case when select_lex.table_list.elements==0
/* find non VIEW subqueries/unions */
- bool selects_allow_merge= select_lex.next_select() == 0;
+ bool selects_allow_merge= (select_lex.next_select() == 0 &&
+ !(select_lex.uncacheable &
+ UNCACHEABLE_RAND));
if (selects_allow_merge)
{
for (SELECT_LEX_UNIT *tmp_unit= select_lex.first_inner_unit();
@@ -3312,6 +3318,7 @@ static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl)
void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
Item **having_conds)
{
+ DBUG_ENTER("st_select_lex::fix_prepare_information");
if (!thd->stmt_arena->is_conventional() && first_execution)
{
first_execution= 0;
@@ -3340,6 +3347,7 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds,
}
fix_prepare_info_in_table_list(thd, table_list.first);
}
+ DBUG_VOID_RETURN;
}
@@ -4077,11 +4085,8 @@ void SELECT_LEX::mark_const_derived(bool empty)
bool st_select_lex::save_leaf_tables(THD *thd)
{
- Query_arena *arena= thd->stmt_arena, backup;
- if (arena->is_conventional())
- arena= 0;
- else
- thd->set_n_backup_active_arena(arena, &backup);
+ Query_arena *arena, backup;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
List_iterator_fast<TABLE_LIST> li(leaf_tables);
TABLE_LIST *table;
@@ -4109,10 +4114,7 @@ bool st_select_lex::save_prep_leaf_tables(THD *thd)
return 0;
Query_arena *arena= thd->stmt_arena, backup;
- if (arena->is_conventional())
- arena= 0;
- else
- thd->set_n_backup_active_arena(arena, &backup);
+ arena= thd->activate_stmt_arena_if_needed(&backup);
List_iterator_fast<TABLE_LIST> li(leaf_tables);
TABLE_LIST *table;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 479fa81edd7..b84aea6c140 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -2641,6 +2641,7 @@ struct LEX: public Query_tables_list
sl->uncacheable|= cause;
un->uncacheable|= cause;
}
+ select_lex.uncacheable|= cause;
}
void set_trg_event_type_for_tables();
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 221ed09c215..15d7e19188e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2221,6 +2221,7 @@ mysql_execute_command(THD *thd)
Rpl_filter *rpl_filter= thd->rpl_filter;
#endif
DBUG_ENTER("mysql_execute_command");
+
#ifdef WITH_PARTITION_STORAGE_ENGINE
thd->work_part_info= 0;
#endif
@@ -5091,6 +5092,7 @@ finish:
DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() ||
thd->in_multi_stmt_transaction_mode());
+ lex->unit.cleanup();
if (! thd->in_sub_stmt)
{
@@ -5122,7 +5124,6 @@ finish:
ha_maria::implicit_commit(thd, FALSE);
#endif
}
- lex->unit.cleanup();
/* Free tables */
THD_STAGE_INFO(thd, stage_closing_tables);
@@ -6739,7 +6740,11 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->schema_table= schema_table;
}
ptr->select_lex= lex->current_select;
- ptr->cacheable_table= 1;
+ /*
+ We can't cache internal temporary tables between prepares as the
+ table may be deleted before next exection.
+ */
+ ptr->cacheable_table= !table->is_derived_table();
ptr->index_hints= index_hints_arg;
ptr->option= option ? option->str : 0;
/* check that used name is unique */
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 3e19a33ee32..5e256522119 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -5225,6 +5225,8 @@ that are reorganised.
}
else if (alter_info->flags & Alter_info::ALTER_REBUILD_PARTITION)
{
+ set_engine_all_partitions(tab_part_info,
+ tab_part_info->default_engine_type);
if (set_part_state(alter_info, tab_part_info, PART_CHANGED))
{
my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD");
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 747e51df16d..c7b7b7948a0 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -192,6 +192,7 @@ mysql_mutex_t LOCK_plugin;
static DYNAMIC_ARRAY plugin_dl_array;
static DYNAMIC_ARRAY plugin_array;
static HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM];
+static MEM_ROOT plugin_mem_root;
static bool reap_needed= false;
static int plugin_array_version=0;
@@ -203,7 +204,7 @@ ulong dlopen_count;
write-lock on LOCK_system_variables_hash is required before modifying
the following variables/structures
*/
-static MEM_ROOT plugin_mem_root;
+static MEM_ROOT plugin_vars_mem_root;
static uint global_variables_dynamic_size= 0;
static HASH bookmark_hash;
@@ -290,8 +291,8 @@ public:
/* prototypes */
-static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv);
-static bool plugin_load_list(MEM_ROOT *, int *, char **, const char *);
+static void plugin_load(MEM_ROOT *tmp_root);
+static bool plugin_load_list(MEM_ROOT *, const char *);
static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *,
int *, char **);
static bool register_builtin(struct st_maria_plugin *, struct st_plugin_int *,
@@ -1037,8 +1038,7 @@ static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
Requires that a write-lock is held on LOCK_system_variables_hash
*/
static bool plugin_add(MEM_ROOT *tmp_root,
- const LEX_STRING *name, LEX_STRING *dl,
- int *argc, char **argv, int report)
+ const LEX_STRING *name, LEX_STRING *dl, int report)
{
struct st_plugin_int tmp;
struct st_maria_plugin *plugin;
@@ -1075,7 +1075,6 @@ static bool plugin_add(MEM_ROOT *tmp_root,
dupes++;
continue; // already installed
}
-
struct st_plugin_int *tmp_plugin_ptr;
if (*(int*)plugin->info <
min_plugin_info_interface_version[plugin->type] ||
@@ -1106,14 +1105,9 @@ static bool plugin_add(MEM_ROOT *tmp_root,
tmp.ref_count= 0;
tmp.state= PLUGIN_IS_UNINITIALIZED;
tmp.load_option= PLUGIN_ON;
- if (test_plugin_options(tmp_root, &tmp, argc, argv))
- tmp.state= PLUGIN_IS_DISABLED;
if (!(tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
- {
- mysql_del_sys_var_chain(tmp.system_vars);
goto err;
- }
plugin_array_version++;
if (my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
tmp_plugin_ptr->state= PLUGIN_IS_FREED;
@@ -1128,8 +1122,6 @@ static bool plugin_add(MEM_ROOT *tmp_root,
err:
errs++;
- if (tmp.nbackups)
- restore_ptr_backup(tmp.nbackups, tmp.ptr_backup);
if (name->str)
break;
}
@@ -1198,6 +1190,8 @@ static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
if (ref_check && plugin->ref_count)
sql_print_error("Plugin '%s' has ref_count=%d after deinitialization.",
plugin->name.str, plugin->ref_count);
+
+ mysql_del_sys_var_chain(plugin->system_vars);
}
static void plugin_del(struct st_plugin_int *plugin)
@@ -1205,11 +1199,8 @@ static void plugin_del(struct st_plugin_int *plugin)
DBUG_ENTER("plugin_del");
mysql_mutex_assert_owner(&LOCK_plugin);
/* Free allocated strings before deleting the plugin. */
- mysql_rwlock_wrlock(&LOCK_system_variables_hash);
- mysql_del_sys_var_chain(plugin->system_vars);
- mysql_rwlock_unlock(&LOCK_system_variables_hash);
- restore_ptr_backup(plugin->nbackups, plugin->ptr_backup);
plugin_vars_free_values(plugin->system_vars);
+ restore_ptr_backup(plugin->nbackups, plugin->ptr_backup);
my_hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
plugin_dl_del(plugin->plugin_dl);
plugin->state= PLUGIN_IS_FREED;
@@ -1343,7 +1334,8 @@ void plugin_unlock_list(THD *thd, plugin_ref *list, uint count)
}
-static int plugin_initialize(struct st_plugin_int *plugin)
+static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin,
+ int *argc, char **argv, bool options_only)
{
int ret= 1;
DBUG_ENTER("plugin_initialize");
@@ -1353,6 +1345,18 @@ static int plugin_initialize(struct st_plugin_int *plugin)
DBUG_ASSERT(state == PLUGIN_IS_UNINITIALIZED);
mysql_mutex_unlock(&LOCK_plugin);
+
+ mysql_rwlock_wrlock(&LOCK_system_variables_hash);
+ if (test_plugin_options(tmp_root, plugin, argc, argv))
+ state= PLUGIN_IS_DISABLED;
+ mysql_rwlock_unlock(&LOCK_system_variables_hash);
+
+ if (options_only || state == PLUGIN_IS_DISABLED)
+ {
+ ret= 0;
+ goto err;
+ }
+
if (plugin_type_initialize[plugin->plugin->type])
{
if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
@@ -1412,6 +1416,9 @@ static int plugin_initialize(struct st_plugin_int *plugin)
ret= 0;
err:
+ if (ret)
+ mysql_del_sys_var_chain(plugin->system_vars);
+
mysql_mutex_lock(&LOCK_plugin);
plugin->state= state;
@@ -1504,6 +1511,7 @@ int plugin_init(int *argc, char **argv, int flags)
#endif
init_alloc_root(&plugin_mem_root, 4096, 4096, MYF(0));
+ init_alloc_root(&plugin_vars_mem_root, 4096, 4096, MYF(0));
init_alloc_root(&tmp_root, 4096, 4096, MYF(0));
if (my_hash_init(&bookmark_hash, &my_charset_bin, 16, 0, 0,
@@ -1571,10 +1579,7 @@ int plugin_init(int *argc, char **argv, int flags)
}
free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
- if (test_plugin_options(&tmp_root, &tmp, argc, argv))
- tmp.state= PLUGIN_IS_DISABLED;
- else
- tmp.state= PLUGIN_IS_UNINITIALIZED;
+ tmp.state= PLUGIN_IS_UNINITIALIZED;
if (register_builtin(plugin, &tmp, &plugin_ptr))
goto err_unlock;
@@ -1589,15 +1594,12 @@ int plugin_init(int *argc, char **argv, int flags)
mysqld --help for all other users, we will only initialize
MyISAM here.
*/
- if (!(flags & PLUGIN_INIT_SKIP_INITIALIZATION) || is_myisam)
+ if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv, !is_myisam &&
+ (flags & PLUGIN_INIT_SKIP_INITIALIZATION)))
{
- if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED &&
- plugin_initialize(plugin_ptr))
- {
- if (mandatory)
- goto err_unlock;
- plugin_ptr->state= PLUGIN_IS_DISABLED;
- }
+ if (mandatory)
+ goto err_unlock;
+ plugin_ptr->state= PLUGIN_IS_DISABLED;
}
/*
@@ -1625,15 +1627,12 @@ int plugin_init(int *argc, char **argv, int flags)
I_List_iterator<i_string> iter(opt_plugin_load_list);
i_string *item;
while (NULL != (item= iter++))
- plugin_load_list(&tmp_root, argc, argv, item->ptr);
+ plugin_load_list(&tmp_root, item->ptr);
if (!(flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE))
- plugin_load(&tmp_root, argc, argv);
+ plugin_load(&tmp_root);
}
- if (flags & PLUGIN_INIT_SKIP_INITIALIZATION)
- goto end;
-
/*
Now we initialize all remaining plugins
*/
@@ -1645,9 +1644,10 @@ int plugin_init(int *argc, char **argv, int flags)
for (i= 0; i < plugin_array.elements; i++)
{
plugin_ptr= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
- if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED)
+ if (plugin_ptr->plugin_dl && plugin_ptr->state == PLUGIN_IS_UNINITIALIZED)
{
- if (plugin_initialize(plugin_ptr))
+ if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv,
+ (flags & PLUGIN_INIT_SKIP_INITIALIZATION)))
{
plugin_ptr->state= PLUGIN_IS_DYING;
*(reap++)= plugin_ptr;
@@ -1674,7 +1674,6 @@ int plugin_init(int *argc, char **argv, int flags)
if (reaped_mandatory_plugin)
goto err;
-end:
free_root(&tmp_root, MYF(0));
DBUG_RETURN(0);
@@ -1713,7 +1712,7 @@ static bool register_builtin(struct st_maria_plugin *plugin,
/*
called only by plugin_init()
*/
-static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
+static void plugin_load(MEM_ROOT *tmp_root)
{
TABLE_LIST tables;
TABLE *table;
@@ -1772,7 +1771,7 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
the mutex here to satisfy the assert
*/
mysql_mutex_lock(&LOCK_plugin);
- if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
+ if (plugin_add(tmp_root, &name, &dl, REPORT_TO_LOG))
sql_print_warning("Couldn't load plugin named '%s' with soname '%s'.",
str_name.c_ptr(), str_dl.c_ptr());
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
@@ -1794,8 +1793,7 @@ end:
/*
called only by plugin_init()
*/
-static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
- const char *list)
+static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
{
char buffer[FN_REFLEN];
LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
@@ -1830,14 +1828,14 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
mysql_mutex_lock(&LOCK_plugin);
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
name.str= 0; // load everything
- if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
+ if (plugin_add(tmp_root, &name, &dl, REPORT_TO_LOG))
goto error;
}
else
{
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
mysql_mutex_lock(&LOCK_plugin);
- if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
+ if (plugin_add(tmp_root, &name, &dl, REPORT_TO_LOG))
goto error;
}
mysql_mutex_unlock(&LOCK_plugin);
@@ -1995,6 +1993,7 @@ void plugin_shutdown(void)
my_hash_free(&bookmark_hash);
free_root(&plugin_mem_root, MYF(0));
+ free_root(&plugin_vars_mem_root, MYF(0));
global_variables_dynamic_size= 0;
@@ -2006,28 +2005,22 @@ void plugin_shutdown(void)
That is, initialize it, and update mysql.plugin table
*/
-static bool finalize_install(THD *thd, TABLE *table, const LEX_STRING *name)
+static bool finalize_install(THD *thd, TABLE *table, const LEX_STRING *name,
+ int *argc, char **argv)
{
struct st_plugin_int *tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN);
int error;
DBUG_ASSERT(tmp);
mysql_mutex_assert_owner(&LOCK_plugin); // because of tmp->state
- if (tmp->state == PLUGIN_IS_DISABLED)
- {
- if (global_system_variables.log_warnings)
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_CANT_INITIALIZE_UDF, ER(ER_CANT_INITIALIZE_UDF),
- name->str, "Plugin is disabled");
- }
- else if (tmp->state != PLUGIN_IS_UNINITIALIZED)
+ if (tmp->state != PLUGIN_IS_UNINITIALIZED)
{
/* already installed */
return 0;
}
else
{
- if (plugin_initialize(tmp))
+ if (plugin_initialize(thd->mem_root, tmp, argc, argv, false))
{
report_error(REPORT_TO_USER, ER_CANT_INITIALIZE_UDF, name->str,
"Plugin initialization function failed.");
@@ -2035,6 +2028,13 @@ static bool finalize_install(THD *thd, TABLE *table, const LEX_STRING *name)
return 1;
}
}
+ if (tmp->state == PLUGIN_IS_DISABLED)
+ {
+ if (global_system_variables.log_warnings)
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_CANT_INITIALIZE_UDF, ER(ER_CANT_INITIALIZE_UDF),
+ name->str, "Plugin is disabled");
+ }
/*
We do not replicate the INSTALL PLUGIN statement. Disable binlogging
@@ -2084,6 +2084,12 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
MYSQL_LOCK_IGNORE_TIMEOUT)))
DBUG_RETURN(TRUE);
+ if (my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL))
+ {
+ report_error(REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str);
+ DBUG_RETURN(TRUE);
+ }
+
/*
Pre-acquire audit plugins for events that may potentially occur
during [UN]INSTALL PLUGIN.
@@ -2110,23 +2116,12 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
mysql_audit_acquire_plugins(thd, event_class_mask);
mysql_mutex_lock(&LOCK_plugin);
- mysql_rwlock_wrlock(&LOCK_system_variables_hash);
-
- if (my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL))
- {
- report_error(REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str);
- goto err;
- }
- error= plugin_add(thd->mem_root, name, &dl, &argc, argv, REPORT_TO_USER);
- if (argv)
- free_defaults(argv);
- mysql_rwlock_unlock(&LOCK_system_variables_hash);
-
+ error= plugin_add(thd->mem_root, name, &dl, REPORT_TO_USER);
if (error)
goto err;
if (name->str)
- error= finalize_install(thd, table, name);
+ error= finalize_install(thd, table, name, &argc, argv);
else
{
st_plugin_dl *plugin_dl= plugin_dl_find(&dl);
@@ -2134,22 +2129,20 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
for (plugin= plugin_dl->plugins; plugin->info; plugin++)
{
LEX_STRING str= { const_cast<char*>(plugin->name), strlen(plugin->name) };
- error|= finalize_install(thd, table, &str);
+ error|= finalize_install(thd, table, &str, &argc, argv);
}
}
if (error)
- goto deinit;
-
- mysql_mutex_unlock(&LOCK_plugin);
- DBUG_RETURN(FALSE);
-
-deinit:
- reap_needed= true;
- reap_plugins();
+ {
+ reap_needed= true;
+ reap_plugins();
+ }
err:
mysql_mutex_unlock(&LOCK_plugin);
- DBUG_RETURN(TRUE);
+ if (argv)
+ free_defaults(argv);
+ DBUG_RETURN(error);
}
@@ -2872,7 +2865,7 @@ static st_bookmark *register_var(const char *plugin, const char *name,
if (!(result= find_bookmark(NULL, varname + 1, flags)))
{
- result= (st_bookmark*) alloc_root(&plugin_mem_root,
+ result= (st_bookmark*) alloc_root(&plugin_vars_mem_root,
sizeof(struct st_bookmark) + length-1);
varname[0]= plugin_var_bookmark_key(flags);
memcpy(result->key, varname, length);
@@ -3840,7 +3833,7 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
enum_plugin_load_option plugin_load_option= tmp->load_option;
MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ?
- &tmp->mem_root : &plugin_mem_root;
+ &tmp->mem_root : &plugin_vars_mem_root;
st_mysql_sys_var **opt;
my_option *opts= NULL;
LEX_STRING plugin_name;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 62c935db544..1450d5c03ea 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -881,7 +881,7 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
if (param->state == Item_param::NO_VALUE)
DBUG_RETURN(1);
- if (param->limit_clause_param)
+ if (param->limit_clause_param && param->state != Item_param::INT_VALUE)
{
param->set_int(param->val_int(), MY_INT64_NUM_DECIMAL_DIGITS);
param->item_type= Item::INT_ITEM;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 1a1a39ad166..dd23400f387 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1078,8 +1078,10 @@ JOIN::optimize_inner()
if (select_lex->handle_derived(thd->lex, DT_MERGE))
DBUG_RETURN(TRUE);
table_count= select_lex->leaf_tables.elements;
- select_lex->update_used_tables();
}
+ // Update used tables after all handling derived table procedures
+ select_lex->update_used_tables();
+
/*
In fact we transform underlying subqueries after their 'prepare' phase and
before 'optimize' from upper query 'optimize' to allow semijoin
@@ -1158,11 +1160,8 @@ TODO: make view to decide if it is possible to write to WHERE directly or make S
MEMROOT for prepared statements and stored procedures.
*/
- Query_arena *arena= thd->stmt_arena, backup;
- if (arena->is_conventional())
- arena= 0; // For easier test
- else
- thd->set_n_backup_active_arena(arena, &backup);
+ Query_arena *arena, backup;
+ arena= thd->activate_stmt_arena_if_needed(&backup);
sel->first_cond_optimization= 0;
@@ -2431,6 +2430,7 @@ void JOIN::exec_inner()
In this case JOIN::exec must check for JOIN::having_value, in the
same way it checks for JOIN::cond_value.
*/
+ DBUG_ASSERT(error == 0);
if (cond_value != Item::COND_FALSE &&
having_value != Item::COND_FALSE &&
(!conds || conds->val_int()) &&
@@ -2441,16 +2441,15 @@ void JOIN::exec_inner()
procedure->end_of_records()) : result->send_data(fields_list)> 0))
error= 1;
else
- {
- error= (int) result->send_eof();
send_records= ((select_options & OPTION_FOUND_ROWS) ? 1 :
thd->get_sent_row_count());
- }
}
else
- {
- error=(int) result->send_eof();
send_records= 0;
+ if (!error)
+ {
+ join_free(); // Unlock all cursors
+ error= (int) result->send_eof();
}
}
/* Single select (without union) always returns 0 or 1 row */
@@ -3391,7 +3390,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
stat_ref=(JOIN_TAB**) join->thd->alloc(sizeof(JOIN_TAB*)*
(MAX_TABLES + table_count + 1));
stat_vector= stat_ref + MAX_TABLES;
- table_vector=(TABLE**) join->thd->alloc(sizeof(TABLE*)*(table_count*2));
+ table_vector=(TABLE**) join->thd->calloc(sizeof(TABLE*)*(table_count*2));
join->positions= new (join->thd->mem_root) POSITION[(table_count+1)];
/*
best_positions is ok to allocate with alloc() as we copy things to it with
@@ -11452,6 +11451,16 @@ void JOIN::cleanup(bool full)
{
tab->cleanup();
}
+
+ if (tabs_kind == WALK_OPTIMIZATION_TABS &&
+ first_breadth_first_tab(this, WALK_OPTIMIZATION_TABS) !=
+ first_breadth_first_tab(this, WALK_EXECUTION_TABS))
+ {
+ JOIN_TAB *jt= first_breadth_first_tab(this, WALK_EXECUTION_TABS);
+ /* We've walked optimization tabs. do execution ones too */
+ if (jt)
+ jt->cleanup();
+ }
}
cleaned= true;
@@ -11672,6 +11681,8 @@ static void update_depend_map_for_order(JOIN *join, ORDER *order)
Remove all constants and check if ORDER only contains simple
expressions.
+ We also remove all duplicate expressions, keeping only the first one.
+
simple_order is set to 1 if sort_order only uses fields from head table
and the head table is not a LEFT JOIN table.
@@ -11679,9 +11690,10 @@ static void update_depend_map_for_order(JOIN *join, ORDER *order)
@param first_order List of SORT or GROUP order
@param cond WHERE statement
@param change_list Set to 1 if we should remove things from list.
- If this is not set, then only simple_order is
- calculated.
- @param simple_order Set to 1 if we are only using simple expressions
+ If this is not set, then only simple_order is
+ calculated.
+ @param simple_order Set to 1 if we are only using simple
+ expressions.
@return
Returns new sort order
@@ -11694,7 +11706,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
if (join->table_count == join->const_tables)
return change_list ? 0 : first_order; // No need to sort
- ORDER *order,**prev_ptr;
+ ORDER *order,**prev_ptr, *tmp_order;
table_map first_table;
table_map not_const_tables= ~join->const_table_map;
table_map ref;
@@ -11708,7 +11720,6 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
first_is_base_table= TRUE;
}
-
/*
Cleanup to avoid interference of calls of this function for
ORDER BY and GROUP BY
@@ -11777,6 +11788,17 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
}
}
}
+ /* Remove ORDER BY entries that we have seen before */
+ for (tmp_order= first_order;
+ tmp_order != order;
+ tmp_order= tmp_order->next)
+ {
+ if (tmp_order->item[0]->eq(order->item[0],1))
+ break;
+ }
+ if (tmp_order != order)
+ continue; // Duplicate order by. Remove
+
if (change_list)
*prev_ptr= order; // use this entry
prev_ptr= &order->next;
@@ -15420,7 +15442,8 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
save_sum_fields|= param->precomputed_group_by;
DBUG_ENTER("create_tmp_table");
DBUG_PRINT("enter",
- ("distinct: %d save_sum_fields: %d rows_limit: %lu group: %d",
+ ("table_alias: '%s' distinct: %d save_sum_fields: %d "
+ "rows_limit: %lu group: %d", table_alias,
(int) distinct, (int) save_sum_fields,
(ulong) rows_limit,test(group)));
@@ -15868,23 +15891,8 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
if (!(field->flags & NOT_NULL_FLAG))
{
- if (field->flags & GROUP_FLAG && !using_unique_constraint)
- {
- /*
- We have to reserve one byte here for NULL bits,
- as this is updated by 'end_update()'
- */
- *pos++=0; // Null is stored here
- recinfo->length=1;
- recinfo->type=FIELD_NORMAL;
- recinfo++;
- bzero((uchar*) recinfo,sizeof(*recinfo));
- }
- else
- {
- recinfo->null_bit= (uint8)1 << (null_count & 7);
- recinfo->null_pos= null_count/8;
- }
+ recinfo->null_bit= (uint8)1 << (null_count & 7);
+ recinfo->null_pos= null_count/8;
field->move_field(pos,null_flags+null_count/8,
(uint8)1 << (null_count & 7));
null_count++;
@@ -16855,7 +16863,8 @@ free_tmp_table(THD *thd, TABLE *entry)
MEM_ROOT own_root= entry->mem_root;
const char *save_proc_info;
DBUG_ENTER("free_tmp_table");
- DBUG_PRINT("enter",("table: %s",entry->alias.c_ptr()));
+ DBUG_PRINT("enter",("table: %s alias: %s",entry->s->table_name.str,
+ entry->alias.c_ptr()));
save_proc_info=thd->proc_info;
THD_STAGE_INFO(thd, stage_removing_tmp_table);
@@ -18815,19 +18824,6 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
goto end;
}
- /*
- Copy null bits from group key to table
- We can't copy all data as the key may have different format
- as the row data (for example as with VARCHAR keys)
- */
- KEY_PART_INFO *key_part;
- for (group=table->group,key_part=table->key_info[0].key_part;
- group ;
- group=group->next,key_part++)
- {
- if (key_part->null_bit)
- memcpy(table->record[0]+key_part->offset, group->buff, 1);
- }
init_tmptable_sum_functions(join->sum_funcs);
if (copy_funcs(join->tmp_table_param.items_to_copy, join->thd))
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
@@ -19481,7 +19477,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
key as a suffix to the secondary keys. If it has continue to check
the primary key as a suffix.
*/
- if (!on_pk_suffix &&
+ if (!on_pk_suffix && (table->key_info[idx].ext_key_part_map & 1) &&
(table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
table->s->primary_key != MAX_KEY &&
table->s->primary_key != idx)
@@ -19505,11 +19501,12 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
(((key_part_map) 1) << pk_part_idx)))
break;
}
+
/* Adjust const_key_parts */
const_key_parts&= (((key_part_map) 1) << pk_part_idx) -1;
- for (; const_key_parts & 1 ; const_key_parts>>= 1)
- key_part++;
+ for (; const_key_parts & 1 ; const_key_parts>>= 1)
+ key_part++;
/*
Test if the primary key parts were all const (i.e. there's one row).
The sorting doesn't matter.
@@ -19518,7 +19515,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
reverse == 0)
{
key_parts= 0;
- reverse= 1;
+ reverse= 1; // Key is ok to use
goto ok;
}
}
@@ -20103,7 +20100,7 @@ check_reverse_order:
table->disable_keyread();
}
}
- else if (tab->type != JT_ALL)
+ else if (tab->type != JT_ALL || tab->select->quick)
{
/*
We're about to use a quick access to the table.
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 17767a2afb3..2ab34ece903 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2220,7 +2220,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
field->maybe_null=1;
field_list.push_back(field=new Item_empty_string("Info",max_query_length));
field->maybe_null=1;
- if (!thd->variables.old_mode)
+ if (!thd->variables.old_mode &&
+ !(thd->variables.old_behavior & OLD_MODE_NO_PROGRESS_INFO))
{
field_list.push_back(field= new Item_float("Progress", 0.0, 3, 7));
field->maybe_null= 0;
@@ -2292,6 +2293,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
(double) tmp->progress.max_counter) /
(double) max_stage)) *
100.0);
+ set_if_smaller(thd_info->progress, 100);
}
else
thd_info->progress= 0.0;
@@ -2326,7 +2328,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
protocol->store(thd_info->state_info, system_charset_info);
protocol->store(thd_info->query_string.str(),
thd_info->query_string.charset());
- if (!thd->variables.old_mode)
+ if (!thd->variables.old_mode &&
+ !(thd->variables.old_behavior & OLD_MODE_NO_PROGRESS_INFO))
protocol->store(thd_info->progress, 3, &store_buffer);
if (protocol->write())
break; /* purecov: inspected */
diff --git a/sql/sql_time.cc b/sql/sql_time.cc
index b194d46643e..5ef7b2c7c34 100644
--- a/sql/sql_time.cc
+++ b/sql/sql_time.cc
@@ -230,6 +230,20 @@ check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
}
+bool
+adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec)
+{
+ MYSQL_TIME copy= *ltime;
+ ErrConvTime str(&copy);
+ int warnings= 0;
+ if (check_time_range(ltime, dec, &warnings))
+ return true;
+ if (warnings)
+ make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ &str, MYSQL_TIMESTAMP_TIME, NullS);
+ return false;
+}
+
/*
Convert a string to 8-bit representation,
for use in str_to_time/str_to_date/str_to_date.
diff --git a/sql/sql_time.h b/sql/sql_time.h
index 6a8c78ecd5e..e27102b15d3 100644
--- a/sql/sql_time.h
+++ b/sql/sql_time.h
@@ -127,5 +127,6 @@ check_date(const MYSQL_TIME *ltime, ulonglong flags, int *was_cut)
}
bool check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
timestamp_type ts_type);
+bool adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec);
#endif /* SQL_TIME_INCLUDED */
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index d143930908d..ff2da863db8 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -653,7 +653,10 @@ bool st_select_lex_unit::exec()
{
ha_rows records_at_start= 0;
thd->lex->current_select= sl;
- fake_select_lex->uncacheable|= sl->uncacheable;
+ if (sl != &thd->lex->select_lex)
+ fake_select_lex->uncacheable|= sl->uncacheable;
+ else
+ fake_select_lex->uncacheable= 0;
{
set_limit(sl);
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index e1c92a81604..5093398fa40 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1093,11 +1093,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
will be TRUE as far as we make new table cache).
*/
old_lex= thd->lex;
- arena= thd->stmt_arena;
- if (arena->is_conventional())
- arena= 0;
- else
- thd->set_n_backup_active_arena(arena, &backup);
+ arena= thd->activate_stmt_arena_if_needed(&backup);
/* init timestamp */
if (!table->timestamp.str)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index f8724943676..3315c2d4d17 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -10263,7 +10263,7 @@ variable_aux:
if ($$ == NULL)
MYSQL_YYABORT;
LEX *lex= Lex;
- lex->uncacheable(UNCACHEABLE_RAND);
+ lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
lex->set_var_list.push_back(item);
}
| ident_or_text
@@ -10272,7 +10272,7 @@ variable_aux:
if ($$ == NULL)
MYSQL_YYABORT;
LEX *lex= Lex;
- lex->uncacheable(UNCACHEABLE_RAND);
+ lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
}
| '@' opt_var_ident_type ident_or_text opt_component
{
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index edd6e7b12a4..77f437243c8 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2002, 2012, Oracle and/or its affiliates.
- Copyright (c) 2012, Monty Program Ab
+/* Copyright (c) 2002, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2012, 2014, SkySQL 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
@@ -1951,7 +1951,7 @@ static Sys_var_ulong Sys_net_retry_count(
ON_UPDATE(fix_net_retry_count));
static Sys_var_mybool Sys_old_mode(
- "old", "Use compatible behavior",
+ "old", "Use compatible behavior from previous MariaDB version. See also --old-mode",
SESSION_VAR(old_mode), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
static Sys_var_mybool Sys_old_alter_table(
@@ -2361,9 +2361,13 @@ static Sys_var_charptr Sys_socket(
static Sys_var_ulong Sys_thread_concurrency(
"thread_concurrency",
"Permits the application to give the threads system a hint for "
- "the desired number of threads that should be run at the same time",
+ "the desired number of threads that should be run at the same time."
+ "This variable has no effect, and is deprecated. "
+ "It will be removed in a future release.",
READ_ONLY GLOBAL_VAR(concurrency), CMD_LINE(REQUIRED_ARG),
- VALID_RANGE(1, 512), DEFAULT(DEFAULT_CONCURRENCY), BLOCK_SIZE(1));
+ VALID_RANGE(1, 512), DEFAULT(DEFAULT_CONCURRENCY), BLOCK_SIZE(1),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0),
+ DEPRECATED(""));
static Sys_var_ulonglong Sys_thread_stack(
"thread_stack", "The stack size for each thread",
@@ -2787,6 +2791,30 @@ static Sys_var_set Sys_sql_mode(
sql_mode_names, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(check_sql_mode), ON_UPDATE(fix_sql_mode));
+static const char *old_mode_names[]=
+{
+ "NO_DUP_KEY_WARNINGS_WITH_IGNORE", "NO_PROGRESS_INFO",
+ 0
+};
+
+export bool old_mode_string_representation(THD *thd, ulonglong sql_mode,
+ LEX_STRING *ls)
+{
+ set_to_string(thd, ls, sql_mode, old_mode_names);
+ return ls->str == 0;
+}
+/*
+ sql_mode should *not* be IN_BINLOG as the slave can't remember this
+ anyway on restart.
+*/
+static Sys_var_set Sys_old_behavior(
+ "old_mode",
+ "Used to emulate old behavior from earlier MariaDB or MySQL versions. "
+ "Syntax: old_mode=mode[,mode[,mode...]]. "
+ "See the manual for the complete list of valid old modes",
+ SESSION_VAR(old_behavior), CMD_LINE(REQUIRED_ARG),
+ old_mode_names, DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG);
+
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
#define SSL_OPT(X) CMD_LINE(REQUIRED_ARG,X)
#else
diff --git a/sql/table.cc b/sql/table.cc
index 08a12b91a7a..87cd2adc542 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -773,7 +773,6 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
keyinfo->ext_key_part_map= 0;
if (share->use_ext_keys && i && !(keyinfo->flags & HA_NOSAME))
{
- keyinfo->ext_key_part_map= 0;
for (j= 0;
j < first_key_parts && keyinfo->ext_key_parts < MAX_REF_PARTS;
j++)
@@ -4126,8 +4125,9 @@ bool TABLE_LIST::create_field_translation(THD *thd)
SELECT_LEX *select= get_single_select();
List_iterator_fast<Item> it(select->item_list);
uint field_count= 0;
- Query_arena *arena= thd->stmt_arena, backup;
+ Query_arena *arena, backup;
bool res= FALSE;
+ DBUG_ENTER("TABLE_LIST::create_field_translation");
if (thd->stmt_arena->is_conventional() ||
thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
@@ -4148,7 +4148,7 @@ bool TABLE_LIST::create_field_translation(THD *thd)
if (field_translation)
{
/*
- Update items in the field translation aftet view have been prepared.
+ Update items in the field translation after view have been prepared.
It's needed because some items in the select list, like IN subselects,
might be substituted for optimized ones.
*/
@@ -4161,13 +4161,10 @@ bool TABLE_LIST::create_field_translation(THD *thd)
field_translation_updated= TRUE;
}
- return FALSE;
+ DBUG_RETURN(FALSE);
}
- if (arena->is_conventional())
- arena= 0; // For easier test
- else
- thd->set_n_backup_active_arena(arena, &backup);
+ arena= thd->activate_stmt_arena_if_needed(&backup);
/* Create view fields translation table */
@@ -4187,12 +4184,14 @@ bool TABLE_LIST::create_field_translation(THD *thd)
}
field_translation= transl;
field_translation_end= transl + field_count;
+ /* It's safe to cache this table for prepared statements */
+ cacheable_table= 1;
exit:
if (arena)
thd->restore_active_arena(arena, &backup);
- return res;
+ DBUG_RETURN(res);
}
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 2026ed425f2..94fcfc7bfcf 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -41,6 +41,8 @@
#include <my_time.h>
#include "tztime.h"
#include <my_sys.h>
+#include <mysql_version.h>
+#include <my_getopt.h>
#endif
#include "tzfile.h"
@@ -63,6 +65,8 @@
#endif /* !defined(DBUG_OFF) */
#endif /* defined(TZINFO2SQL) || defined(TESTTIME) */
+#define PROGRAM_VERSION "1.1"
+
/* Structure describing local time type (e.g. Moscow summer time (MSD)) */
typedef struct ttinfo
{
@@ -2387,7 +2391,6 @@ void Time_zone::adjust_leap_second(MYSQL_TIME *t)
tables.
*/
-
/*
Print info about time zone described by TIME_ZONE_INFO struct as
SQL statements populating mysql.time_zone* tables.
@@ -2472,6 +2475,15 @@ MEM_ROOT tz_storage;
char fullname[FN_REFLEN + 1];
char *root_name_end;
+/*
+ known file types that exist in the zoneinfo directory that are safe to
+ silently skip
+*/
+const char *known_extensions[]= {
+ ".tab",
+ NullS
+};
+
/*
Recursively scan zoneinfo directory and print all found time zone
@@ -2480,6 +2492,8 @@ char *root_name_end;
SYNOPSIS
scan_tz_dir()
name_end - pointer to end of path to directory to be searched.
+ symlink_recursion_level How many symlink directory levels are used
+ verbose >0 if we should print warnings
DESCRIPTION
This auxiliary recursive function also uses several global
@@ -2495,7 +2509,7 @@ char *root_name_end;
*/
my_bool
-scan_tz_dir(char * name_end, uint symlink_recursion_level)
+scan_tz_dir(char * name_end, uint symlink_recursion_level, uint verbose)
{
MY_DIR *cur_dir;
char *name_end_tmp;
@@ -2536,12 +2550,21 @@ scan_tz_dir(char * name_end, uint symlink_recursion_level)
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);
+
+ /*
+ This is a normal case and not critical. only print warning if
+ verbose mode is choosen.
+ */
+ if (verbose > 0)
+ {
+ 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))
+ if (scan_tz_dir(name_end_tmp, symlink_recursion_level + is_symlink,
+ verbose))
{
my_dirend(cur_dir);
return 1;
@@ -2554,10 +2577,28 @@ scan_tz_dir(char * name_end, uint symlink_recursion_level)
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);
+ /*
+ Some systems (like debian, opensuse etc) have description
+ files (.tab). We skip these silently if verbose is > 0
+ */
+ const char *current_ext= fn_ext(fullname);
+ my_bool known_ext= 0;
+
+ for (const char **ext= known_extensions ; *ext ; ext++)
+ {
+ if (!strcmp(*ext, current_ext))
+ {
+ known_ext= 1;
+ break;
+ }
+ }
+ if (verbose > 0 || !known_ext)
+ {
+ fflush(stdout);
+ fprintf(stderr,
+ "Warning: Unable to load '%s' as time zone. Skipping it.\n",
+ fullname);
+ }
}
free_root(&tz_storage, MYF(0));
}
@@ -2576,34 +2617,114 @@ scan_tz_dir(char * name_end, uint symlink_recursion_level)
}
+my_bool opt_leap, opt_verbose;
+
+static const char *load_default_groups[]=
+{ "mysql_tzinfo_to_sql", 0};
+
+static struct my_option my_long_options[] =
+{
+ {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
+#ifdef DBUG_OFF
+ {"debug", '#', "This is a non-debug version. Catch this and exit",
+ 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#else
+ {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
+ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"leap", 'l', "Print the leap second information from the given time zone file. By convention, when --leap is used the next argument is the timezonefile",
+ &opt_leap, &opt_leap, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"verbose", 'v', "Write non critical warnings",
+ &opt_verbose, &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"version", 'V', "Output version information and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+
+C_MODE_START
+static my_bool get_one_option(int optid, const struct my_option *,
+ char *argument);
+C_MODE_END
+
+static void print_version(void)
+{
+ printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname, PROGRAM_VERSION,
+ MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
+}
+
+static void print_usage(void)
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, " %s [options] timezonedir\n", my_progname);
+ fprintf(stderr, " %s [options] timezonefile timezonename\n", my_progname);
+ print_defaults("my",load_default_groups);
+ puts("");
+ my_print_help(my_long_options);
+ my_print_variables(my_long_options);
+}
+
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt, char *argument)
+{
+ switch(optid) {
+ case '#':
+#ifndef DBUG_OFF
+ DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysq_tzinfo_to_sql.trace");
+#endif
+ break;
+ case '?':
+ print_version();
+ puts("");
+ print_usage();
+ exit(0);
+ case 'V':
+ print_version();
+ exit(0);
+ }
+ return 0;
+}
+
+
int
main(int argc, char **argv)
{
+ char **default_argv;
MY_INIT(argv[0]);
- if (argc != 2 && argc != 3)
+ if (load_defaults("my",load_default_groups,&argc,&argv))
+ exit(1);
+
+ default_argv= argv;
+
+ if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
+ exit(1);
+
+ if ((argc != 1 && argc != 2) || (opt_leap && argc != 1))
{
- fprintf(stderr, "Usage:\n");
- fprintf(stderr, " %s timezonedir\n", argv[0]);
- fprintf(stderr, " %s timezonefile timezonename\n", argv[0]);
- fprintf(stderr, " %s --leap timezonefile\n", argv[0]);
+ print_usage();
+ free_defaults(default_argv);
return 1;
}
-
- if (argc == 2)
+ if (argc == 1 && !opt_leap)
{
- root_name_end= strmake_buf(fullname, argv[1]);
+ /* Argument is timezonedir */
+
+ root_name_end= strmake_buf(fullname, argv[0]);
printf("TRUNCATE TABLE time_zone;\n");
printf("TRUNCATE TABLE time_zone_name;\n");
printf("TRUNCATE TABLE time_zone_transition;\n");
printf("TRUNCATE TABLE time_zone_transition_type;\n");
- if (scan_tz_dir(root_name_end, 0))
+ if (scan_tz_dir(root_name_end, 0, opt_verbose))
{
fflush(stdout);
- fprintf(stderr, "There were fatal errors during processing "
- "of zoneinfo directory\n");
+ fprintf(stderr,
+ "There were fatal errors during processing "
+ "of zoneinfo directory '%s'\n", fullname);
return 1;
}
@@ -2614,32 +2735,27 @@ main(int argc, char **argv)
}
else
{
+ /*
+ First argument is timezonefile.
+ The second is timezonename if opt_leap is not given
+ */
init_alloc_root(&tz_storage, 32768, 0, MYF(0));
- if (strcmp(argv[1], "--leap") == 0)
+ if (tz_load(argv[0], &tz_info, &tz_storage))
{
- if (tz_load(argv[2], &tz_info, &tz_storage))
- {
- fflush(stdout);
- fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
- return 1;
- }
- print_tz_leaps_as_sql(&tz_info);
+ fflush(stdout);
+ fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[0]);
+ return 1;
}
+ if (opt_leap)
+ print_tz_leaps_as_sql(&tz_info);
else
- {
- if (tz_load(argv[1], &tz_info, &tz_storage))
- {
- fflush(stdout);
- fprintf(stderr, "Problems with zoneinfo file '%s'\n", argv[2]);
- return 1;
- }
- print_tz_as_sql(argv[2], &tz_info);
- }
+ print_tz_as_sql(argv[1], &tz_info);
free_root(&tz_storage, MYF(0));
}
+ free_defaults(default_argv);
my_end(0);
return 0;
}