summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2015-10-12 00:37:58 +0200
committerSergei Golubchik <serg@mariadb.org>2015-10-12 00:37:58 +0200
commitdfb74dea300f83880c11600dc726a9cae559f356 (patch)
tree76da0d6e23f188bc13520bf80496e9053f227d9a /sql
parentb785857d00a0fd9c98cb52823357bfad8fb18289 (diff)
parente7cb032e560e14865941ecdcb553cd3aba856b68 (diff)
downloadmariadb-git-dfb74dea300f83880c11600dc726a9cae559f356.tar.gz
Merge branch '10.0' into 10.1
Diffstat (limited to 'sql')
-rw-r--r--sql/field.h20
-rw-r--r--sql/field_conv.cc16
-rw-r--r--sql/item_cmpfunc.cc54
-rw-r--r--sql/item_func.cc50
-rw-r--r--sql/item_func.h42
-rw-r--r--sql/item_subselect.cc28
-rw-r--r--sql/item_subselect.h6
-rw-r--r--sql/log_event.cc131
-rw-r--r--sql/log_event.h74
-rw-r--r--sql/log_slow.h28
-rw-r--r--sql/mysqld.cc18
-rw-r--r--sql/opt_range.cc20
-rw-r--r--sql/opt_subselect.cc49
-rw-r--r--sql/partition_info.cc53
-rw-r--r--sql/slave.cc6
-rw-r--r--sql/sql_acl.cc56
-rw-r--r--sql/sql_admin.h2
-rw-r--r--sql/sql_base.cc14
-rw-r--r--sql/sql_class.cc15
-rw-r--r--sql/sql_const.h4
-rw-r--r--sql/sql_handler.cc37
-rw-r--r--sql/sql_handler.h5
-rw-r--r--sql/sql_insert.cc44
-rw-r--r--sql/sql_load.cc13
-rw-r--r--sql/sql_parse.cc44
-rw-r--r--sql/sql_repl.cc19
-rw-r--r--sql/sql_select.cc5
-rw-r--r--sql/sql_show.cc19
-rw-r--r--sql/sql_yacc.yy10
-rw-r--r--sql/threadpool_unix.cc2
-rw-r--r--sql/unireg.h12
31 files changed, 664 insertions, 232 deletions
diff --git a/sql/field.h b/sql/field.h
index 6cd435f2bec..b24561d7dd9 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1,6 +1,6 @@
#ifndef FIELD_INCLUDED
#define FIELD_INCLUDED
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
Copyright (c) 2008, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
@@ -1308,6 +1308,16 @@ public:
/* Hash value */
virtual void hash(ulong *nr, ulong *nr2);
+/**
+ Checks whether a string field is part of write_set.
+
+ @return
+ FALSE - If field is not char/varchar/....
+ - If field is char/varchar/.. and is not part of write set.
+ TRUE - If field is char/varchar/.. and is part of write set.
+*/
+ virtual bool is_updatable() const { return FALSE; }
+
/* Check whether the field can be used as a join attribute in hash join */
virtual bool hash_join_is_possible() { return TRUE; }
virtual bool eq_cmp_as_binary() { return TRUE; }
@@ -1582,6 +1592,14 @@ public:
int store_decimal(const my_decimal *d);
uint32 max_data_length() const;
+
+ bool is_updatable() const
+ {
+ DBUG_ASSERT(table && table->write_set);
+ return bitmap_is_set(table->write_set, field_index);
+ }
+ bool match_collation_to_optimize_range() const { return true; }
+
bool can_optimize_keypart_ref(const Item_bool_func *cond,
const Item *item) const;
bool can_optimize_hash_join(const Item_bool_func *cond,
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 14f2947eba7..0ad8cee0c3b 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -1,7 +1,6 @@
/*
- Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 2010, 2012, Monty Program Ab
-
+ Copyright (c) 2000, 2015, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -906,15 +905,10 @@ int field_conv_incompatible(Field *to, Field *from)
{ // Be sure the value is stored
Field_blob *blob=(Field_blob*) to;
from->val_str(&blob->value);
- /*
- Copy value if copy_blobs is set, or source is not a string and
- we have a pointer to its internal string conversion buffer.
- */
- if (to->table->copy_blobs ||
- (!blob->value.is_alloced() &&
- from_real_type != MYSQL_TYPE_STRING &&
- from_real_type != MYSQL_TYPE_VARCHAR))
+
+ if (!blob->value.is_alloced() && from->is_updatable())
blob->value.copy();
+
return blob->store(blob->value.ptr(),blob->value.length(),from->charset());
}
if (from_real_type == MYSQL_TYPE_ENUM &&
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 764ca000e99..c968ff6f65e 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1236,9 +1236,36 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *opt_arg)
bool Item_in_optimizer::fix_left(THD *thd)
{
DBUG_ENTER("Item_in_optimizer::fix_left");
- if ((!args[0]->fixed && args[0]->fix_fields(thd, args)) ||
- (!cache && !(cache= Item_cache::get_cache(thd, args[0]))))
+ /*
+ Here we will store pointer on place of main storage of left expression.
+ For usual IN (ALL/ANY) it is subquery left_expr.
+ For other cases (MAX/MIN optimization, non-transformed EXISTS (10.0))
+ it is args[0].
+ */
+ Item **ref0= args;
+ if (args[1]->type() == Item::SUBSELECT_ITEM &&
+ ((Item_subselect *)args[1])->is_in_predicate())
+ {
+ /*
+ left_expr->fix_fields() may cause left_expr to be substituted for
+ another item. (e.g. an Item_field may be changed into Item_ref). This
+ transformation is undone at the end of statement execution (e.g. the
+ Item_ref is deleted). However, Item_in_optimizer::args[0] may keep
+ the pointer to the post-transformation item. Because of that, on the
+ next execution we need to copy args[1]->left_expr again.
+ */
+ ref0= &(((Item_in_subselect *)args[1])->left_expr);
+ args[0]= ((Item_in_subselect *)args[1])->left_expr;
+ }
+ if ((!(*ref0)->fixed && (*ref0)->fix_fields(thd, ref0)) ||
+ (!cache && !(cache= Item_cache::get_cache(thd, *ref0))))
DBUG_RETURN(1);
+ /*
+ During fix_field() expression could be substituted.
+ So we copy changes before use
+ */
+ if (args[0] != (*ref0))
+ args[0]= (*ref0);
DBUG_PRINT("info", ("actual fix fields"));
cache->setup(thd, args[0]);
@@ -1300,6 +1327,16 @@ bool Item_in_optimizer::fix_left(THD *thd)
bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
{
DBUG_ASSERT(fixed == 0);
+ Item_subselect *sub= 0;
+ uint col;
+
+ /*
+ MAX/MIN optimization can convert the subquery into
+ expr + Item_singlerow_subselect
+ */
+ if (args[1]->type() == Item::SUBSELECT_ITEM)
+ sub= (Item_subselect *)args[1];
+
if (fix_left(thd))
return TRUE;
if (args[0]->maybe_null)
@@ -1307,12 +1344,11 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
if (!args[1]->fixed && args[1]->fix_fields(thd, args+1))
return TRUE;
-
- Item_in_subselect * sub= (Item_in_subselect *)args[1];
if (!invisible_mode() &&
- args[0]->cols() != sub->engine->cols())
+ ((sub && ((col= args[0]->cols()) != sub->engine->cols())) ||
+ (!sub && (args[1]->cols() != (col= 1)))))
{
- my_error(ER_OPERAND_COLUMNS, MYF(0), args[0]->cols());
+ my_error(ER_OPERAND_COLUMNS, MYF(0), col);
return TRUE;
}
if (args[1]->maybe_null)
@@ -2469,7 +2505,8 @@ Item_func_if::str_op(String *str)
String *res=arg->val_str(str);
if (res)
res->set_charset(collation.collation);
- null_value=arg->null_value;
+ if ((null_value=arg->null_value))
+ res= NULL;
return res;
}
@@ -2480,7 +2517,8 @@ Item_func_if::decimal_op(my_decimal *decimal_value)
DBUG_ASSERT(fixed == 1);
Item *arg= args[0]->val_bool() ? args[1] : args[2];
my_decimal *value= arg->val_decimal(decimal_value);
- null_value= arg->null_value;
+ if ((null_value= arg->null_value))
+ value= NULL;
return value;
}
diff --git a/sql/item_func.cc b/sql/item_func.cc
index ed6722fac4a..edfb6741b69 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -875,7 +875,7 @@ String *Item_func_hybrid_field_type::val_str(String *str)
case DECIMAL_RESULT:
{
my_decimal decimal_value, *val;
- if (!(val= decimal_op(&decimal_value)))
+ if (!(val= decimal_op_with_null_check(&decimal_value)))
return 0; // null is set
my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val);
str->set_charset(collation.collation);
@@ -901,23 +901,21 @@ String *Item_func_hybrid_field_type::val_str(String *str)
case TIME_RESULT:
{
MYSQL_TIME ltime;
- if (date_op(&ltime,
- field_type() == MYSQL_TYPE_TIME ? TIME_TIME_ONLY : 0) ||
- str->alloc(MAX_DATE_STRING_REP_LENGTH))
- {
- null_value= 1;
+ if (date_op_with_null_check(&ltime) ||
+ (null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH)))
return (String *) 0;
- }
ltime.time_type= mysql_type_to_time_type(field_type());
str->length(my_TIME_to_str(&ltime, const_cast<char*>(str->ptr()), decimals));
str->set_charset(&my_charset_bin);
+ DBUG_ASSERT(!null_value);
return str;
}
case STRING_RESULT:
- return str_op(&str_value);
+ return str_op_with_null_check(&str_value);
case ROW_RESULT:
DBUG_ASSERT(0);
}
+ DBUG_ASSERT(!null_value || (str == NULL));
return str;
}
@@ -930,7 +928,7 @@ double Item_func_hybrid_field_type::val_real()
{
my_decimal decimal_value, *val;
double result;
- if (!(val= decimal_op(&decimal_value)))
+ if (!(val= decimal_op_with_null_check(&decimal_value)))
return 0.0; // null is set
my_decimal2double(E_DEC_FATAL_ERROR, val, &result);
return result;
@@ -945,18 +943,14 @@ double Item_func_hybrid_field_type::val_real()
case TIME_RESULT:
{
MYSQL_TIME ltime;
- if (date_op(&ltime,
- field_type() == MYSQL_TYPE_TIME ? TIME_TIME_ONLY : 0 ))
- {
- null_value= 1;
+ if (date_op_with_null_check(&ltime))
return 0;
- }
ltime.time_type= mysql_type_to_time_type(field_type());
return TIME_to_double(&ltime);
}
case STRING_RESULT:
{
- String *res= str_op(&str_value);
+ String *res= str_op_with_null_check(&str_value);
return res ? double_from_string_with_check(res) : 0.0;
}
case ROW_RESULT:
@@ -973,7 +967,7 @@ longlong Item_func_hybrid_field_type::val_int()
case DECIMAL_RESULT:
{
my_decimal decimal_value, *val;
- if (!(val= decimal_op(&decimal_value)))
+ if (!(val= decimal_op_with_null_check(&decimal_value)))
return 0; // null is set
longlong result;
my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
@@ -986,18 +980,14 @@ longlong Item_func_hybrid_field_type::val_int()
case TIME_RESULT:
{
MYSQL_TIME ltime;
- if (date_op(&ltime,
- field_type() == MYSQL_TYPE_TIME ? TIME_TIME_ONLY : 0))
- {
- null_value= 1;
+ if (date_op_with_null_check(&ltime))
return 0;
- }
ltime.time_type= mysql_type_to_time_type(field_type());
return TIME_to_ulonglong(&ltime);
}
case STRING_RESULT:
{
- String *res= str_op(&str_value);
+ String *res= str_op_with_null_check(&str_value);
return res ? longlong_from_string_with_check(res) : 0;
}
case ROW_RESULT:
@@ -1013,28 +1003,30 @@ my_decimal *Item_func_hybrid_field_type::val_decimal(my_decimal *decimal_value)
DBUG_ASSERT(fixed == 1);
switch (Item_func_hybrid_field_type::cmp_type()) {
case DECIMAL_RESULT:
- val= decimal_op(decimal_value);
+ val= decimal_op_with_null_check(decimal_value);
break;
case INT_RESULT:
{
longlong result= int_op();
+ if (null_value)
+ return NULL;
int2my_decimal(E_DEC_FATAL_ERROR, result, unsigned_flag, decimal_value);
break;
}
case REAL_RESULT:
{
double result= (double)real_op();
+ if (null_value)
+ return NULL;
double2my_decimal(E_DEC_FATAL_ERROR, result, decimal_value);
break;
}
case TIME_RESULT:
{
MYSQL_TIME ltime;
- if (date_op(&ltime,
- field_type() == MYSQL_TYPE_TIME ? TIME_TIME_ONLY : 0))
+ if (date_op_with_null_check(&ltime))
{
my_decimal_set_zero(decimal_value);
- null_value= 1;
return 0;
}
ltime.time_type= mysql_type_to_time_type(field_type());
@@ -1042,7 +1034,7 @@ my_decimal *Item_func_hybrid_field_type::val_decimal(my_decimal *decimal_value)
}
case STRING_RESULT:
{
- String *res= str_op(&str_value);
+ String *res= str_op_with_null_check(&str_value);
return res ? decimal_from_string_with_check(decimal_value, res) : 0;
}
case ROW_RESULT:
@@ -1060,7 +1052,7 @@ bool Item_func_hybrid_field_type::get_date(MYSQL_TIME *ltime,
case DECIMAL_RESULT:
{
my_decimal value, *res;
- if (!(res= decimal_op(&value)) ||
+ if (!(res= decimal_op_with_null_check(&value)) ||
decimal_to_datetime_with_warn(res, ltime, fuzzydate,
field_name_or_null()))
goto err;
@@ -1092,7 +1084,7 @@ bool Item_func_hybrid_field_type::get_date(MYSQL_TIME *ltime,
{
char buff[40];
String tmp(buff,sizeof(buff), &my_charset_bin),*res;
- if (!(res= str_op(&tmp)) ||
+ if (!(res= str_op_with_null_check(&tmp)) ||
str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
ltime, fuzzydate))
goto err;
diff --git a/sql/item_func.h b/sql/item_func.h
index d524e62c374..3bcd1ede386 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -338,17 +338,17 @@ public:
void no_rows_in_result()
{
- bool_func_call_args info;
- info.original_func_item= this;
- info.bool_function= &Item::no_rows_in_result;
- walk(&Item::call_bool_func_processor, FALSE, (uchar*) &info);
+ for (uint i= 0; i < arg_count; i++)
+ {
+ args[i]->no_rows_in_result();
+ }
}
void restore_to_before_no_rows_in_result()
{
- bool_func_call_args info;
- info.original_func_item= this;
- info.bool_function= &Item::restore_to_before_no_rows_in_result;
- walk(&Item::call_bool_func_processor, FALSE, (uchar*) &info);
+ for (uint i= 0; i < arg_count; i++)
+ {
+ args[i]->no_rows_in_result();
+ }
}
void convert_const_compared_to_int_field(THD *thd);
/**
@@ -425,6 +425,32 @@ public:
*/
class Item_func_hybrid_field_type: public Item_hybrid_func
{
+ /*
+ Helper methods to make sure that the result of
+ decimal_op(), str_op() and date_op() is properly synched with null_value.
+ */
+ bool date_op_with_null_check(MYSQL_TIME *ltime)
+ {
+ bool rc= date_op(ltime,
+ field_type() == MYSQL_TYPE_TIME ? TIME_TIME_ONLY : 0);
+ DBUG_ASSERT(!rc ^ null_value);
+ return rc;
+ }
+ String *str_op_with_null_check(String *str)
+ {
+ String *res= str_op(str);
+ DBUG_ASSERT((res != NULL) ^ null_value);
+ return res;
+ }
+ my_decimal *decimal_op_with_null_check(my_decimal *decimal_buffer)
+ {
+ my_decimal *res= decimal_op(decimal_buffer);
+ DBUG_ASSERT((res != NULL) ^ null_value);
+ return res;
+ }
+protected:
+ Item_result cached_result_type;
+
public:
Item_func_hybrid_field_type(THD *thd):
Item_hybrid_func(thd)
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index ddfe90fed59..84c21bf2fad 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1394,7 +1394,7 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp,
{
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
DBUG_PRINT("info", ("in_strategy: %u", (uint)in_strategy));
- left_expr= left_exp;
+ left_expr_orig= left_expr= left_exp;
func= &eq_creator;
init(select_lex, new (thd->mem_root) select_exists_subselect(thd, this));
max_columns= UINT_MAX;
@@ -1417,7 +1417,7 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp,
Item_in_subselect(thd), func_creator(fc), all(all_arg)
{
DBUG_ENTER("Item_allany_subselect::Item_allany_subselect");
- left_expr= left_exp;
+ left_expr_orig= left_expr= left_exp;
func= func_creator(all_arg);
init(select_lex, new (thd->mem_root) select_exists_subselect(thd, this));
max_columns= 1;
@@ -3083,15 +3083,13 @@ Item_in_subselect::select_in_like_transformer(JOIN *join)
arena= thd->activate_stmt_arena_if_needed(&backup);
if (!optimizer)
{
- result= (!(optimizer= new (thd->mem_root) Item_in_optimizer(thd, left_expr, this)));
- if (result)
+ optimizer= new (thd->mem_root) Item_in_optimizer(thd, left_expr_orig, this);
+ if ((result= !optimizer))
goto out;
}
thd->lex->current_select= current->return_after_parsing();
result= optimizer->fix_left(thd);
- /* fix_fields can change reference to left_expr, we need reassign it */
- left_expr= optimizer->arguments()[0];
thd->lex->current_select= current;
if (changed)
@@ -3158,11 +3156,13 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref)
{
uint outer_cols_num;
List<Item> *inner_cols;
+ char const *save_where= thd->where;
DBUG_ENTER("Item_in_subselect::fix_fields");
if (test_strategy(SUBS_SEMI_JOIN))
DBUG_RETURN( !( (*ref)= new (thd->mem_root) Item_int(thd, 1)) );
+ thd->where= "IN/ALL/ANY subquery";
/*
Check if the outer and inner IN operands match in those cases when we
will not perform IN=>EXISTS transformation. Currently this is when we
@@ -3193,7 +3193,7 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref)
if (outer_cols_num != inner_cols->elements)
{
my_error(ER_OPERAND_COLUMNS, MYF(0), outer_cols_num);
- DBUG_RETURN(TRUE);
+ goto err;
}
if (outer_cols_num > 1)
{
@@ -3203,20 +3203,24 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref)
{
inner_col= inner_col_it++;
if (inner_col->check_cols(left_expr->element_index(i)->cols()))
- DBUG_RETURN(TRUE);
+ goto err;
}
}
}
- if (thd_arg->lex->is_view_context_analysis() &&
- left_expr && !left_expr->fixed &&
+ if (left_expr && !left_expr->fixed &&
left_expr->fix_fields(thd_arg, &left_expr))
- DBUG_RETURN(TRUE);
+ goto err;
else
if (Item_subselect::fix_fields(thd_arg, ref))
- DBUG_RETURN(TRUE);
+ goto err;
fixed= TRUE;
+ thd->where= save_where;
DBUG_RETURN(FALSE);
+
+err:
+ thd->where= save_where;
+ DBUG_RETURN(TRUE);
}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 27d06d715b5..670d0a66639 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -481,6 +481,12 @@ protected:
Item **having_item);
public:
Item *left_expr;
+ /*
+ Important for PS/SP: left_expr_orig is the item that left_expr originally
+ pointed at. That item is allocated on the statement arena, while
+ left_expr could later be changed to something on the execution arena.
+ */
+ Item *left_expr_orig;
/* Priority of this predicate in the convert-to-semi-join-nest process. */
int sj_convert_priority;
/*
diff --git a/sql/log_event.cc b/sql/log_event.cc
index a2a2b814cf9..544e67fb287 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -308,7 +308,7 @@ public:
~Write_on_release_cache()
{
copy_event_cache_to_file_and_reinit(m_cache, m_file);
- if (m_flags | FLUSH_F)
+ if (m_flags & FLUSH_F)
fflush(m_file);
}
@@ -817,6 +817,15 @@ const char* Log_event::get_type_str(Log_event_type type)
case GTID_EVENT: return "Gtid";
case GTID_LIST_EVENT: return "Gtid_list";
case START_ENCRYPTION_EVENT: return "Start_encryption";
+
+ /* The following is only for mysqlbinlog */
+ case IGNORABLE_LOG_EVENT: return "Ignorable log event";
+ case ROWS_QUERY_LOG_EVENT: return "MySQL Rows_query";
+ case GTID_LOG_EVENT: return "MySQL Gtid";
+ case ANONYMOUS_GTID_LOG_EVENT: return "MySQL Anonymous_Gtid";
+ case PREVIOUS_GTIDS_LOG_EVENT: return "MySQL Previous_gtids";
+ case HEARTBEAT_LOG_EVENT: return "Heartbeat";
+
default: return "Unknown"; /* impossible */
}
}
@@ -1541,9 +1550,11 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
DBUG_PRINT("info", ("binlog_version: %d", fdle->binlog_version));
DBUG_DUMP_EVENT_BUF(buf, event_len);
- /* Check the integrity */
- if (event_len < EVENT_LEN_OFFSET ||
- (uchar)buf[EVENT_TYPE_OFFSET] >= ENUM_END_EVENT)
+ /*
+ Check the integrity; This is needed because handle_slave_io() doesn't
+ check if packet is of proper length.
+ */
+ if (event_len < EVENT_LEN_OFFSET)
{
*error="Sanity check failed"; // Needed to free buffer
DBUG_RETURN(NULL); // general sanity check - will fail on a partial read
@@ -1720,6 +1731,15 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
case DELETE_ROWS_EVENT:
ev = new Delete_rows_log_event(buf, event_len, fdle);
break;
+
+ /* MySQL GTID events are ignored */
+ case GTID_LOG_EVENT:
+ case ANONYMOUS_GTID_LOG_EVENT:
+ case PREVIOUS_GTIDS_LOG_EVENT:
+ ev= new Ignorable_log_event(buf, fdle,
+ get_type_str((Log_event_type) event_type));
+ break;
+
case TABLE_MAP_EVENT:
ev = new Table_map_log_event(buf, event_len, fdle);
break;
@@ -1740,10 +1760,22 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
ev = new Start_encryption_log_event(buf, event_len, fdle);
break;
default:
- DBUG_PRINT("error",("Unknown event code: %d",
- (int) buf[EVENT_TYPE_OFFSET]));
- ev= NULL;
- break;
+ /*
+ Create an object of Ignorable_log_event for unrecognized sub-class.
+ So that SLAVE SQL THREAD will only update the position and continue.
+ */
+ if (uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F)
+ {
+ ev= new Ignorable_log_event(buf, fdle,
+ get_type_str((Log_event_type) event_type));
+ }
+ else
+ {
+ DBUG_PRINT("error",("Unknown event code: %d",
+ (int) buf[EVENT_TYPE_OFFSET]));
+ ev= NULL;
+ break;
+ }
}
}
@@ -2211,19 +2243,12 @@ log_event_print_value(IO_CACHE *file, const uchar *ptr,
uint precision= meta >> 8;
uint decimals= meta & 0xFF;
uint bin_size= my_decimal_get_binary_size(precision, decimals);
- uint length;
my_decimal dec;
binary2my_decimal(E_DEC_FATAL_ERROR, (uchar*) ptr, &dec,
precision, decimals);
- int i, end;
- char buff[512], *pos;
- pos= buff;
- pos+= sprintf(buff, "%s", dec.sign() ? "-" : "");
- end= ROUND_UP(dec.frac) + ROUND_UP(dec.intg)-1;
- for (i=0; i < end; i++)
- pos+= sprintf(pos, "%09d.", dec.buf[i]);
- pos+= sprintf(pos, "%09d", dec.buf[i]);
- length= (uint) (pos - buff);
+ int length= DECIMAL_MAX_STR_LENGTH;
+ char buff[DECIMAL_MAX_STR_LENGTH + 1];
+ decimal2string(&dec, buff, &length, 0, 0, 0);
my_b_write(file, (uchar*)buff, length);
my_snprintf(typestr, typestr_length, "DECIMAL(%d,%d)",
precision, decimals);
@@ -4890,6 +4915,9 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
post_header_len[HEARTBEAT_LOG_EVENT-1]= 0;
post_header_len[IGNORABLE_LOG_EVENT-1]= 0;
post_header_len[ROWS_QUERY_LOG_EVENT-1]= 0;
+ post_header_len[GTID_LOG_EVENT-1]= 0;
+ post_header_len[ANONYMOUS_GTID_LOG_EVENT-1]= 0;
+ post_header_len[PREVIOUS_GTIDS_LOG_EVENT-1]= 0;
post_header_len[WRITE_ROWS_EVENT-1]= ROWS_HEADER_LEN_V2;
post_header_len[UPDATE_ROWS_EVENT-1]= ROWS_HEADER_LEN_V2;
post_header_len[DELETE_ROWS_EVENT-1]= ROWS_HEADER_LEN_V2;
@@ -12618,6 +12646,52 @@ Incident_log_event::write_data_body()
}
#endif
+Ignorable_log_event::Ignorable_log_event(const char *buf,
+ const Format_description_log_event
+ *descr_event,
+ const char *event_name)
+ :Log_event(buf, descr_event), number((int) (uchar) buf[EVENT_TYPE_OFFSET]),
+ description(event_name)
+{
+ DBUG_ENTER("Ignorable_log_event::Ignorable_log_event");
+ DBUG_VOID_RETURN;
+}
+
+Ignorable_log_event::~Ignorable_log_event()
+{
+}
+
+#ifndef MYSQL_CLIENT
+/* Pack info for its unrecognized ignorable event */
+void Ignorable_log_event::pack_info(THD *thd, Protocol *protocol)
+{
+ char buf[256];
+ size_t bytes;
+ bytes= my_snprintf(buf, sizeof(buf), "# Ignorable event type %d (%s)",
+ number, description);
+ protocol->store(buf, bytes, &my_charset_bin);
+}
+#endif
+
+#ifdef MYSQL_CLIENT
+/* Print for its unrecognized ignorable event */
+void
+Ignorable_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ if (print_event_info->short_form)
+ return;
+
+ print_header(&print_event_info->head_cache, print_event_info, FALSE);
+ my_b_printf(&print_event_info->head_cache, "\tIgnorable\n");
+ my_b_printf(&print_event_info->head_cache,
+ "# Ignorable event type %d (%s)\n", number, description);
+ copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
+ file);
+}
+#endif
+
+
#ifdef MYSQL_CLIENT
/**
The default values for these variables should be values that are
@@ -12699,4 +12773,25 @@ bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos,
return TRUE;
#endif
}
+
+/**
+ Check if we should write event to the relay log
+
+ This is used to skip events that is only supported by MySQL
+
+ Return:
+ 0 ok
+ 1 Don't write event
+*/
+
+bool event_that_should_be_ignored(const char *buf)
+{
+ uint event_type= (uchar)buf[EVENT_TYPE_OFFSET];
+ if (event_type == GTID_LOG_EVENT ||
+ event_type == ANONYMOUS_GTID_LOG_EVENT ||
+ event_type == PREVIOUS_GTIDS_LOG_EVENT ||
+ (uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F))
+ return 1;
+ return 0;
+}
#endif
diff --git a/sql/log_event.h b/sql/log_event.h
index f96075db77d..4d22be61d16 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -207,6 +207,7 @@ class String;
#define EXECUTE_LOAD_QUERY_HEADER_LEN (QUERY_HEADER_LEN + EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN)
#define INCIDENT_HEADER_LEN 2
#define HEARTBEAT_HEADER_LEN 0
+#define IGNORABLE_HEADER_LEN 0
#define ROWS_HEADER_LEN_V2 10
#define ANNOTATE_ROWS_HEADER_LEN 0
#define BINLOG_CHECKPOINT_HEADER_LEN 4
@@ -243,7 +244,7 @@ class String;
to the slave. It is used to increase the thd(max_allowed) for both the
DUMP thread on the master and the SQL/IO thread on the slave.
*/
-#define MAX_MAX_ALLOWED_PACKET 1024*1024*1024
+#define MAX_MAX_ALLOWED_PACKET (1024*1024*1024)
/*
Event header offsets;
@@ -468,6 +469,17 @@ class String;
#define LOG_EVENT_RELAY_LOG_F 0x40
/**
+ @def LOG_EVENT_IGNORABLE_F
+
+ For an event, 'e', carrying a type code, that a slave,
+ 's', does not recognize, 's' will check 'e' for
+ LOG_EVENT_IGNORABLE_F, and if the flag is set, then 'e'
+ is ignored. Otherwise, 's' acknowledges that it has
+ found an unknown event in the relay log.
+*/
+#define LOG_EVENT_IGNORABLE_F 0x80
+
+/**
@def LOG_EVENT_SKIP_REPLICATION_F
Flag set by application creating the event (with @@skip_replication); the
@@ -636,6 +648,11 @@ enum Log_event_type
UPDATE_ROWS_EVENT = 31,
DELETE_ROWS_EVENT = 32,
+ /* MySQL 5.6 GTID events, ignored by MariaDB */
+ GTID_LOG_EVENT= 33,
+ ANONYMOUS_GTID_LOG_EVENT= 34,
+ PREVIOUS_GTIDS_LOG_EVENT= 35,
+
/*
Add new events here - right above this comment!
Existing events (except ENUM_END_EVENT) should never change their numbers
@@ -4814,6 +4831,60 @@ private:
LEX_STRING m_message;
};
+/**
+ @class Ignorable_log_event
+
+ Base class for ignorable log events. Events deriving from
+ this class can be safely ignored by slaves that cannot
+ recognize them. Newer slaves, will be able to read and
+ handle them. This has been designed to be an open-ended
+ architecture, so adding new derived events shall not harm
+ the old slaves that support ignorable log event mechanism
+ (they will just ignore unrecognized ignorable events).
+
+ @note The only thing that makes an event ignorable is that it has
+ the LOG_EVENT_IGNORABLE_F flag set. It is not strictly necessary
+ that ignorable event types derive from Ignorable_log_event; they may
+ just as well derive from Log_event and pass LOG_EVENT_IGNORABLE_F as
+ argument to the Log_event constructor.
+**/
+
+class Ignorable_log_event : public Log_event {
+public:
+ int number;
+ const char *description;
+
+#ifndef MYSQL_CLIENT
+ Ignorable_log_event(THD *thd_arg)
+ :Log_event(thd_arg, LOG_EVENT_IGNORABLE_F, FALSE),
+ number(0), description("internal")
+ {
+ DBUG_ENTER("Ignorable_log_event::Ignorable_log_event");
+ DBUG_VOID_RETURN;
+ }
+#endif
+
+ Ignorable_log_event(const char *buf,
+ const Format_description_log_event *descr_event,
+ const char *event_name);
+ virtual ~Ignorable_log_event();
+
+#ifndef MYSQL_CLIENT
+ void pack_info(THD *, Protocol*);
+#endif
+
+#ifdef MYSQL_CLIENT
+ virtual void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+#endif
+
+ virtual Log_event_type get_type_code() { return IGNORABLE_LOG_EVENT; }
+
+ virtual bool is_valid() const { return 1; }
+
+ virtual int get_data_size() { return IGNORABLE_HEADER_LEN; }
+};
+
+
static inline bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache,
FILE *file)
{
@@ -4878,6 +4949,7 @@ bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos,
const char **group_relay_log_name,
ulonglong *relay_log_pos);
+bool event_that_should_be_ignored(const char *buf);
bool event_checksum_test(uchar *buf, ulong event_len, enum_binlog_checksum_alg alg);
enum enum_binlog_checksum_alg get_checksum_alg(const char* buf, ulong len);
extern TYPELIB binlog_checksum_typelib;
diff --git a/sql/log_slow.h b/sql/log_slow.h
index 2ae07da97c3..3ae2060cc27 100644
--- a/sql/log_slow.h
+++ b/sql/log_slow.h
@@ -16,23 +16,23 @@
/* Defining what to log to slow log */
#define LOG_SLOW_VERBOSITY_INIT 0
-#define LOG_SLOW_VERBOSITY_INNODB 1 << 0
-#define LOG_SLOW_VERBOSITY_QUERY_PLAN 1 << 1
-#define LOG_SLOW_VERBOSITY_EXPLAIN 1 << 2
+#define LOG_SLOW_VERBOSITY_INNODB (1 << 0)
+#define LOG_SLOW_VERBOSITY_QUERY_PLAN (1 << 1)
+#define LOG_SLOW_VERBOSITY_EXPLAIN (1 << 2)
#define QPLAN_INIT QPLAN_QC_NO
-#define QPLAN_ADMIN 1 << 0
-#define QPLAN_FILESORT 1 << 1
-#define QPLAN_FILESORT_DISK 1 << 2
-#define QPLAN_FULL_JOIN 1 << 3
-#define QPLAN_FULL_SCAN 1 << 4
-#define QPLAN_QC 1 << 5
-#define QPLAN_QC_NO 1 << 6
-#define QPLAN_TMP_DISK 1 << 7
-#define QPLAN_TMP_TABLE 1 << 8
-#define QPLAN_FILESORT_PRIORITY_QUEUE 1 << 9
+#define QPLAN_ADMIN (1 << 0)
+#define QPLAN_FILESORT (1 << 1)
+#define QPLAN_FILESORT_DISK (1 << 2)
+#define QPLAN_FULL_JOIN (1 << 3)
+#define QPLAN_FULL_SCAN (1 << 4)
+#define QPLAN_QC (1 << 5)
+#define QPLAN_QC_NO (1 << 6)
+#define QPLAN_TMP_DISK (1 << 7)
+#define QPLAN_TMP_TABLE (1 << 8)
+#define QPLAN_FILESORT_PRIORITY_QUEUE (1 << 9)
/* ... */
-#define QPLAN_MAX ((ulong) 1) << 31 /* reserved as placeholder */
+#define QPLAN_MAX (((ulong) 1) << 31) /* reserved as placeholder */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index c85f6520a1d..23b3c210dc7 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4552,14 +4552,24 @@ static int init_common_variables()
{
if (lower_case_table_names_used)
{
+#if MYSQL_VERSION_ID < 100100
if (global_system_variables.log_warnings)
sql_print_warning("You have forced lower_case_table_names to 0 through "
"a command-line option, even though your file system "
"'%s' is case insensitive. This means that you can "
- "corrupt a MyISAM table by accessing it with "
- "different cases. You should consider changing "
- "lower_case_table_names to 1 or 2",
- mysql_real_data_home);
+ "corrupt your tables if you access them using names "
+ "with different letter case. You should consider "
+ "changing lower_case_table_names to 1 or 2",
+ mysql_real_data_home);
+#else
+ sql_print_error("The server option 'lower_case_table_names' is "
+ "configured to use case sensitive table names but the "
+ "data directory resides on a case-insensitive file system. "
+ "Please use a case sensitive file system for your data "
+ "directory or switch to a case-insensitive table name "
+ "mode.");
+#endif
+ return 1;
}
else
{
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index a6fb7f7793c..64d476c1327 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2008, 2014, Monty Program Ab.
+/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -2511,6 +2511,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.key_parts_end=key_parts;
param.alloced_sel_args= 0;
+ max_key_len++; /* Take into account the "+1" in QUICK_RANGE::QUICK_RANGE */
if (!(param.min_key= (uchar*)alloc_root(&alloc,max_key_len)) ||
!(param.max_key= (uchar*)alloc_root(&alloc,max_key_len)))
{
@@ -2770,6 +2771,7 @@ bool create_key_parts_for_pseudo_indexes(RANGE_OPT_PARAM *param,
}
}
+ max_key_len++; /* Take into account the "+1" in QUICK_RANGE::QUICK_RANGE */
if (!(param->min_key= (uchar*)alloc_root(param->mem_root, max_key_len)) ||
!(param->max_key= (uchar*)alloc_root(param->mem_root, max_key_len)))
{
@@ -4039,10 +4041,19 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
key_tree->min_flag |
key_tree->max_flag,
&subpart_iter);
- DBUG_ASSERT(res); /* We can't get "no satisfying subpartitions" */
+ if (res == 0)
+ {
+ /*
+ The only case where we can get "no satisfying subpartitions"
+ returned from the above call is when an error has occurred.
+ */
+ DBUG_ASSERT(range_par->thd->is_error());
+ return 0;
+ }
+
if (res == -1)
goto pop_and_go_right; /* all subpartitions satisfy */
-
+
uint32 subpart_id;
bitmap_clear_all(&ppar->subparts_bitmap);
while ((subpart_id= subpart_iter.get_next(&subpart_iter)) !=
@@ -4370,6 +4381,7 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
if (cur_key_len > max_key_len)
max_key_len= cur_key_len;
+ max_key_len++; /* Take into account the "+1" in QUICK_RANGE::QUICK_RANGE */
if (!(range_par->min_key= (uchar*)alloc_root(alloc,max_key_len)) ||
!(range_par->max_key= (uchar*)alloc_root(alloc,max_key_len)))
{
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 9c6784437a7..1566ab43074 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -617,6 +617,18 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
thd->stmt_arena->state != Query_arena::PREPARED)
*/
{
+ SELECT_LEX *current= thd->lex->current_select;
+ thd->lex->current_select= current->return_after_parsing();
+ char const *save_where= thd->where;
+ thd->where= "IN/ALL/ANY subquery";
+
+ bool failure= !in_subs->left_expr->fixed &&
+ in_subs->left_expr->fix_fields(thd, &in_subs->left_expr);
+ thd->lex->current_select= current;
+ thd->where= save_where;
+ if (failure)
+ DBUG_RETURN(-1); /* purecov: deadcode */
+
/*
Check if the left and right expressions have the same # of
columns, i.e. we don't have a case like
@@ -630,18 +642,6 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
my_error(ER_OPERAND_COLUMNS, MYF(0), in_subs->left_expr->cols());
DBUG_RETURN(-1);
}
-
- SELECT_LEX *current= thd->lex->current_select;
- thd->lex->current_select= current->return_after_parsing();
- char const *save_where= thd->where;
- thd->where= "IN/ALL/ANY subquery";
-
- bool failure= !in_subs->left_expr->fixed &&
- in_subs->left_expr->fix_fields(thd, &in_subs->left_expr);
- thd->lex->current_select= current;
- thd->where= save_where;
- if (failure)
- DBUG_RETURN(-1); /* purecov: deadcode */
}
DBUG_PRINT("info", ("Checking if subq can be converted to semi-join"));
@@ -705,6 +705,12 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
if (!optimizer_flag(thd, OPTIMIZER_SWITCH_IN_TO_EXISTS) &&
!optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION))
my_error(ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES, MYF(0));
+ /*
+ Transform each subquery predicate according to its overloaded
+ transformer.
+ */
+ if (subselect->select_transformer(join))
+ DBUG_RETURN(-1);
/*
If the subquery predicate is IN/=ANY, analyse and set all possible
@@ -757,12 +763,6 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
allany_subs->add_strategy(strategy);
}
- /*
- Transform each subquery predicate according to its overloaded
- transformer.
- */
- if (subselect->select_transformer(join))
- DBUG_RETURN(-1);
}
}
DBUG_RETURN(0);
@@ -1597,9 +1597,20 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
{
nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr,
thd->mem_root);
+ /*
+ Create Item_func_eq. Note that
+ 1. this is done on the statement, not execution, arena
+ 2. if it's a PS then this happens only once - on the first execution.
+ On following re-executions, the item will be fix_field-ed normally.
+ 3. Thus it should be created as if it was fix_field'ed, in particular
+ all pointers to items in the execution arena should be protected
+ with thd->change_item_tree
+ */
Item_func_eq *item_eq=
- new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr,
+ new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr_orig,
subq_lex->ref_pointer_array[0]);
+ if (subq_pred->left_expr_orig != subq_pred->left_expr)
+ thd->change_item_tree(item_eq->arguments(), subq_pred->left_expr);
item_eq->in_equality_no= 0;
sj_nest->sj_on_expr= and_items(thd, sj_nest->sj_on_expr, item_eq);
}
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index f16ed0e879e..a92c7686eaf 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -1,4 +1,5 @@
-/* Copyright (c) 2006, 2013, Oracle and/or its affiliates.
+/* Copyright (c) 2006, 2015, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -69,7 +70,7 @@ partition_info *partition_info::get_clone(THD *thd)
part_clone->subpartitions.empty();
while ((subpart= (subpart_it++)))
{
- partition_element *subpart_clone= new partition_element();
+ partition_element *subpart_clone= new (mem_root) partition_element();
if (!subpart_clone)
{
mem_alloc_error(sizeof(partition_element));
@@ -79,6 +80,41 @@ partition_info *partition_info::get_clone(THD *thd)
part_clone->subpartitions.push_back(subpart_clone, mem_root);
}
clone->partitions.push_back(part_clone, mem_root);
+ part_clone->list_val_list.empty();
+ List_iterator<part_elem_value> list_val_it(part->list_val_list);
+ part_elem_value *new_val_arr=
+ (part_elem_value *)alloc_root(mem_root, sizeof(part_elem_value) *
+ part->list_val_list.elements);
+ if (!new_val_arr)
+ {
+ mem_alloc_error(sizeof(part_elem_value) * part->list_val_list.elements);
+ DBUG_RETURN(NULL);
+ }
+ p_column_list_val *new_colval_arr=
+ (p_column_list_val*)alloc_root(mem_root, sizeof(p_column_list_val) *
+ num_columns *
+ part->list_val_list.elements);
+ if (!new_colval_arr)
+ {
+ mem_alloc_error(sizeof(p_column_list_val) * num_columns *
+ part->list_val_list.elements);
+ DBUG_RETURN(NULL);
+ }
+ part_elem_value *val;
+ while ((val= list_val_it++))
+ {
+ part_elem_value *new_val= new_val_arr++;
+ memcpy(new_val, val, sizeof(part_elem_value));
+ if (!val->null_value)
+ {
+ p_column_list_val *new_colval= new_colval_arr;
+ new_colval_arr+= num_columns;
+ memcpy(new_colval, val->col_val_array,
+ sizeof(p_column_list_val) * num_columns);
+ new_val->col_val_array= new_colval;
+ }
+ part_clone->list_val_list.push_back(new_val, mem_root);
+ }
}
DBUG_RETURN(clone);
}
@@ -1627,15 +1663,22 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
{
int err= 0;
+ /* Check for partition expression. */
if (!list_of_part_fields)
{
DBUG_ASSERT(part_expr);
err= part_expr->walk(&Item::check_partition_func_processor, 0,
NULL);
- if (!err && is_sub_partitioned() && !list_of_subpart_fields)
- err= subpart_expr->walk(&Item::check_partition_func_processor, 0,
- NULL);
}
+
+ /* Check for sub partition expression. */
+ if (!err && is_sub_partitioned() && !list_of_subpart_fields)
+ {
+ DBUG_ASSERT(subpart_expr);
+ err= subpart_expr->walk(&Item::check_partition_func_processor, 0,
+ NULL);
+ }
+
if (err)
{
my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
diff --git a/sql/slave.cc b/sql/slave.cc
index 6e5bfedf89b..fed171bcc4c 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -5692,6 +5692,11 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
error_msg.append_ulonglong(hb.log_pos);
goto err;
}
+
+ /*
+ Heartbeat events doesn't count in the binlog size, so we don't have to
+ increment mi->master_log_pos
+ */
goto skip_relay_logging;
}
break;
@@ -5972,6 +5977,7 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
else
if ((s_id == global_system_variables.server_id &&
!mi->rli.replicate_same_server_id) ||
+ event_that_should_be_ignored(buf) ||
/*
the following conjunction deals with IGNORE_SERVER_IDS, if set
If the master is on the ignore list, execution of
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 061a227004f..679bd152a39 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -6894,16 +6894,18 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
for (tl= tables; number-- ; tl= tl->next_global)
{
- sctx= MY_TEST(tl->security_ctx) ? tl->security_ctx : thd->security_ctx;
+ TABLE_LIST *const t_ref=
+ tl->correspondent_table ? tl->correspondent_table : tl;
+ sctx= t_ref->security_ctx ? t_ref->security_ctx : thd->security_ctx;
const ACL_internal_table_access *access=
- get_cached_table_access(&tl->grant.m_internal,
- tl->get_db_name(),
- tl->get_table_name());
+ get_cached_table_access(&t_ref->grant.m_internal,
+ t_ref->get_db_name(),
+ t_ref->get_table_name());
if (access)
{
- switch(access->check(orig_want_access, &tl->grant.privilege))
+ switch(access->check(orig_want_access, &t_ref->grant.privilege))
{
case ACL_INTERNAL_ACCESS_GRANTED:
/*
@@ -6927,26 +6929,26 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
if (!want_access)
continue; // ok
- if (!(~tl->grant.privilege & want_access) ||
- tl->is_anonymous_derived_table() || tl->schema_table)
+ if (!(~t_ref->grant.privilege & want_access) ||
+ t_ref->is_anonymous_derived_table() || t_ref->schema_table)
{
/*
- It is subquery in the FROM clause. VIEW set tl->derived after
+ It is subquery in the FROM clause. VIEW set t_ref->derived after
table opening, but this function always called before table opening.
*/
- if (!tl->referencing_view)
+ if (!t_ref->referencing_view)
{
/*
If it's a temporary table created for a subquery in the FROM
clause, or an INFORMATION_SCHEMA table, drop the request for
a privilege.
*/
- tl->grant.want_privilege= 0;
+ t_ref->grant.want_privilege= 0;
}
continue;
}
- if (is_temporary_table(tl))
+ if (is_temporary_table(t_ref))
{
/*
If this table list element corresponds to a pre-opened temporary
@@ -6954,8 +6956,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
Note that during creation of temporary table we still need to check
if user has CREATE_TMP_ACL.
*/
- tl->grant.privilege|= TMP_TABLE_ACLS;
- tl->grant.want_privilege= 0;
+ t_ref->grant.privilege|= TMP_TABLE_ACLS;
+ t_ref->grant.want_privilege= 0;
continue;
}
@@ -6966,20 +6968,20 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
}
grant_table= table_hash_search(sctx->host, sctx->ip,
- tl->get_db_name(),
+ t_ref->get_db_name(),
sctx->priv_user,
- tl->get_table_name(),
+ t_ref->get_table_name(),
FALSE);
if (sctx->priv_role[0])
- grant_table_role= table_hash_search("", NULL, tl->get_db_name(),
+ grant_table_role= table_hash_search("", NULL, t_ref->get_db_name(),
sctx->priv_role,
- tl->get_table_name(),
+ t_ref->get_table_name(),
TRUE);
if (!grant_table && !grant_table_role)
{
- want_access&= ~tl->grant.privilege;
- goto err;
+ want_access&= ~t_ref->grant.privilege;
+ goto err; // No grants
}
/*
@@ -6989,19 +6991,19 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
if (any_combination_will_do)
continue;
- tl->grant.grant_table_user= grant_table; // Remember for column test
- tl->grant.grant_table_role= grant_table_role;
- tl->grant.version= grant_version;
- tl->grant.privilege|= grant_table ? grant_table->privs : 0;
- tl->grant.privilege|= grant_table_role ? grant_table_role->privs : 0;
- tl->grant.want_privilege= ((want_access & COL_ACLS) & ~tl->grant.privilege);
+ t_ref->grant.grant_table_user= grant_table; // Remember for column test
+ t_ref->grant.grant_table_role= grant_table_role;
+ t_ref->grant.version= grant_version;
+ t_ref->grant.privilege|= grant_table ? grant_table->privs : 0;
+ t_ref->grant.privilege|= grant_table_role ? grant_table_role->privs : 0;
+ t_ref->grant.want_privilege= ((want_access & COL_ACLS) & ~t_ref->grant.privilege);
- if (!(~tl->grant.privilege & want_access))
+ if (!(~t_ref->grant.privilege & want_access))
continue;
if ((want_access&= ~((grant_table ? grant_table->cols : 0) |
(grant_table_role ? grant_table_role->cols : 0) |
- tl->grant.privilege)))
+ t_ref->grant.privilege)))
{
goto err; // impossible
}
diff --git a/sql/sql_admin.h b/sql/sql_admin.h
index 77fc41e2ec4..96594fad0cb 100644
--- a/sql/sql_admin.h
+++ b/sql/sql_admin.h
@@ -17,7 +17,7 @@
#define SQL_TABLE_MAINTENANCE_H
/* Must be able to hold ALTER TABLE t PARTITION BY ... KEY ALGORITHM = 1 ... */
-#define SQL_ADMIN_MSG_TEXT_SIZE 128 * 1024
+#define SQL_ADMIN_MSG_TEXT_SIZE (128 * 1024)
bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list,
LEX_STRING *key_cache_name);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index add5532dfc6..ecceec2cffe 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1137,13 +1137,20 @@ bool close_temporary_tables(THD *thd)
DBUG_RETURN(FALSE);
DBUG_ASSERT(!thd->rgi_slave);
+ /*
+ Ensure we don't have open HANDLERs for tables we are about to close.
+ This is necessary when close_temporary_tables() is called as part
+ of execution of BINLOG statement (e.g. for format description event).
+ */
+ mysql_ha_rm_temporary_tables(thd);
if (!mysql_bin_log.is_open())
{
TABLE *tmp_next;
- for (table= thd->temporary_tables; table; table= tmp_next)
+ for (TABLE *t= thd->temporary_tables; t; t= tmp_next)
{
- tmp_next= table->next;
- close_temporary(table, 1, 1);
+ tmp_next= t->next;
+ mysql_lock_remove(thd, thd->lock, t);
+ close_temporary(t, 1, 1);
}
thd->temporary_tables= 0;
DBUG_RETURN(FALSE);
@@ -1239,6 +1246,7 @@ bool close_temporary_tables(THD *thd)
strlen(table->s->table_name.str));
s_query.append(',');
next= table->next;
+ mysql_lock_remove(thd, thd->lock, table);
close_temporary(table, 1, 1);
}
thd->clear_error();
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 0a0d3ca034e..2e899295d23 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -5514,16 +5514,13 @@ int xid_cache_iterate(THD *thd, my_hash_walk_action action, void *arg)
BINLOG_FORMAT = STATEMENT and at least one table uses a storage
engine limited to row-logging.
- 6. Error: Cannot execute row injection: binlogging impossible since
- BINLOG_FORMAT = STATEMENT.
-
- 7. Warning: Unsafe statement binlogged in statement format since
+ 6. Warning: Unsafe statement binlogged in statement format since
BINLOG_FORMAT = STATEMENT.
In addition, we can produce the following error (not depending on
the variables of the decision diagram):
- 8. Error: Cannot execute statement: binlogging impossible since more
+ 7. Error: Cannot execute statement: binlogging impossible since more
than one engine is involved and at least one engine is
self-logging.
@@ -5802,10 +5799,10 @@ int THD::decide_logging_format(TABLE_LIST *tables)
if (lex->is_stmt_row_injection())
{
/*
- 6. Error: Cannot execute row injection since
- BINLOG_FORMAT = STATEMENT
+ We have to log the statement as row or give an error.
+ Better to accept what master gives us than stopping replication.
*/
- my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
+ set_current_stmt_binlog_format_row();
}
else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0 &&
sqlcom_can_generate_row_events(this))
@@ -5833,7 +5830,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
binlog_unsafe_warning_flags));
}
- /* log in statement format! */
+ /* log in statement format (or row if row event)! */
}
/* No statement-only engines and binlog_format != STATEMENT.
I.e., nothing prevents us from row logging if needed. */
diff --git a/sql/sql_const.h b/sql/sql_const.h
index c8bb442376e..f856362f4e5 100644
--- a/sql/sql_const.h
+++ b/sql/sql_const.h
@@ -142,7 +142,7 @@
*/
#define STACK_MIN_SIZE 16000 // Abort if less stack during eval.
-#define STACK_MIN_SIZE_FOR_OPEN 1024*80
+#define STACK_MIN_SIZE_FOR_OPEN (1024*80)
#define STACK_BUFF_ALLOC 352 ///< For stack overrun checks
#ifndef MYSQLD_NET_RETRY_COUNT
#define MYSQLD_NET_RETRY_COUNT 10 ///< Abort read after this many int.
@@ -238,7 +238,7 @@
#define DEFAULT_CONCURRENCY 10
#define DELAYED_LIMIT 100 /**< pause after xxx inserts */
#define DELAYED_QUEUE_SIZE 1000
-#define DELAYED_WAIT_TIMEOUT 5*60 /**< Wait for delayed insert */
+#define DELAYED_WAIT_TIMEOUT (5*60) /**< Wait for delayed insert */
#define MAX_CONNECT_ERRORS 100 ///< errors before disabling host
#define LONG_TIMEOUT ((ulong) 3600L*24L*365L)
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 7dcc6fa0e95..673af54ffeb 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2001, 2013, Oracle and/or its affiliates.
- Copyright (c) 2011, 2013, Monty Program Ab.
+/* Copyright (c) 2001, 2015, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -1190,3 +1190,36 @@ void mysql_ha_set_explicit_lock_duration(THD *thd)
DBUG_VOID_RETURN;
}
+
+/**
+ Remove temporary tables from the HANDLER's hash table. The reason
+ for having a separate function, rather than calling
+ mysql_ha_rm_tables() is that it is not always feasible (e.g. in
+ close_temporary_tables) to obtain a TABLE_LIST containing the
+ temporary tables.
+
+ @See close_temporary_tables
+ @param thd Thread identifier.
+*/
+void mysql_ha_rm_temporary_tables(THD *thd)
+{
+ DBUG_ENTER("mysql_ha_rm_temporary_tables");
+
+ TABLE_LIST *tmp_handler_tables= NULL;
+ for (uint i= 0; i < thd->handler_tables_hash.records; i++)
+ {
+ TABLE_LIST *handler_table= reinterpret_cast<TABLE_LIST*>
+ (my_hash_element(&thd->handler_tables_hash, i));
+
+ if (handler_table->table && handler_table->table->s->tmp_table)
+ {
+ handler_table->next_local= tmp_handler_tables;
+ tmp_handler_tables= handler_table;
+ }
+ }
+
+ if (tmp_handler_tables)
+ mysql_ha_rm_tables(thd, tmp_handler_tables);
+
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/sql_handler.h b/sql/sql_handler.h
index 133f553675e..7fe5ae5bba8 100644
--- a/sql/sql_handler.h
+++ b/sql/sql_handler.h
@@ -1,6 +1,8 @@
#ifndef SQL_HANDLER_INCLUDED
#define SQL_HANDLER_INCLUDED
-/* Copyright (C) 2010 Monty Program Ab
+/* Copyright (c) 2006, 2015, Oracle and/or its affiliates.
+ Copyright (C) 2010, 2015, MariaDB
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
@@ -73,6 +75,7 @@ void mysql_ha_flush_tables(THD *thd, TABLE_LIST *all_tables);
void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables);
void mysql_ha_cleanup(THD *thd);
void mysql_ha_set_explicit_lock_duration(THD *thd);
+void mysql_ha_rm_temporary_tables(THD *thd);
SQL_HANDLER *mysql_ha_read_prepare(THD *thd, TABLE_LIST *tables,
enum enum_ha_read_modes mode, char *keyname,
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 6aa6deaaa08..488826acd70 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2010, 2014, SkySQL Ab.
+ Copyright (c) 2000, 2015, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -3944,15 +3944,35 @@ static TABLE *create_table_from_items(THD *thd,
while ((item=it++))
{
- Create_field *cr_field;
- Field *field= item->create_field_for_create_select(thd, &tmp_table);
- if (!field ||
- !(cr_field= (new (thd->mem_root)
- Create_field(thd, field,
- (item->type() == Item::FIELD_ITEM ?
- ((Item_field *) item)->field :
- (Field *) 0)))))
- DBUG_RETURN(0);
+ Field *tmp_field= item->create_field_for_create_select(thd, &tmp_table);
+
+ if (!tmp_field)
+ DBUG_RETURN(NULL);
+
+ Field *table_field;
+
+ switch (item->type())
+ {
+ /*
+ We have to take into account both the real table's fields and
+ pseudo-fields used in trigger's body. These fields are used
+ to copy defaults values later inside constructor of
+ the class Create_field.
+ */
+ case Item::FIELD_ITEM:
+ case Item::TRIGGER_FIELD_ITEM:
+ table_field= ((Item_field *) item)->field;
+ break;
+ default:
+ table_field= NULL;
+ }
+
+ Create_field *cr_field= new (thd->mem_root)
+ Create_field(thd, tmp_field, table_field);
+
+ if (!cr_field)
+ DBUG_RETURN(NULL);
+
if (item->maybe_null)
cr_field->flags &= ~NOT_NULL_FLAG;
alter_info->create_list.push_back(cr_field, thd->mem_root);
@@ -4042,7 +4062,7 @@ static TABLE *create_table_from_items(THD *thd,
{
if (!thd->is_error()) // CREATE ... IF NOT EXISTS
my_ok(thd); // succeed, but did nothing
- DBUG_RETURN(0);
+ DBUG_RETURN(NULL);
}
DEBUG_SYNC(thd,"create_table_select_before_lock");
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 2870e90ef4d..9cf82c1c6d0 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2010, 2014, SkySQL Ab.
+ Copyright (c) 2000, 2015, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -1999,8 +1999,15 @@ int READ_INFO::read_xml(THD *thd)
break;
case '/': /* close tag */
- level--;
chr= my_tospace(GET);
+ /* Decrease the 'level' only when (i) It's not an */
+ /* (without space) empty tag i.e. <tag/> or, (ii) */
+ /* It is of format <row col="val" .../> */
+ if(chr != '>' || in_tag)
+ {
+ level--;
+ in_tag= false;
+ }
if(chr != '>') /* if this is an empty tag <tag /> */
tag.length(0); /* we should keep tag value */
while(chr != '>' && chr != my_b_EOF)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 257b5d985bc..d6e5082bae6 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates.
- Copyright (c) 2008, 2014, SkySQL Ab.
+/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
+ Copyright (c) 2008, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -3998,7 +3998,10 @@ end_with_restore_list:
if (lex->analyze_stmt)
((select_result_interceptor*)sel_result)->disable_my_ok_calls();
- res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE);
+ if (explain)
+ res= mysql_explain_union(thd, &thd->lex->unit, sel_result);
+ else
+ res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE);
/*
Invalidate the table in the query cache if something changed
after unlocking when changes become visible.
@@ -4014,6 +4017,16 @@ end_with_restore_list:
query_cache_invalidate3(thd, first_table, 1);
first_table->next_local= save_table;
}
+ if (explain)
+ {
+ /*
+ sel_result needs to be cleaned up properly.
+ INSERT... SELECT statement will call either send_eof() or
+ abort_result_set(). EXPLAIN doesn't call either, so we need
+ to cleanup manually.
+ */
+ sel_result->abort_result_set();
+ }
delete sel_result;
}
@@ -6404,9 +6417,12 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
for (; i < number && tables != first_not_own_table && tables;
tables= tables->next_global, i++)
{
+ TABLE_LIST *const table_ref= tables->correspondent_table ?
+ tables->correspondent_table : tables;
+
ulong want_access= requirements;
- if (tables->security_ctx)
- sctx= tables->security_ctx;
+ if (table_ref->security_ctx)
+ sctx= table_ref->security_ctx;
else
sctx= backup_ctx;
@@ -6414,26 +6430,26 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
Register access for view underlying table.
Remove SHOW_VIEW_ACL, because it will be checked during making view
*/
- tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
+ table_ref->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
- if (tables->schema_table_reformed)
+ if (table_ref->schema_table_reformed)
{
- if (check_show_access(thd, tables))
+ if (check_show_access(thd, table_ref))
goto deny;
continue;
}
- DBUG_PRINT("info", ("derived: %d view: %d", tables->derived != 0,
- tables->view != 0));
+ DBUG_PRINT("info", ("derived: %d view: %d", table_ref->derived != 0,
+ table_ref->view != 0));
- if (tables->is_anonymous_derived_table())
+ if (table_ref->is_anonymous_derived_table())
continue;
thd->security_ctx= sctx;
- if (check_access(thd, want_access, tables->get_db_name(),
- &tables->grant.privilege,
- &tables->grant.m_internal,
+ if (check_access(thd, want_access, table_ref->get_db_name(),
+ &table_ref->grant.privilege,
+ &table_ref->grant.m_internal,
0, no_errors))
goto deny;
}
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 5cf55d89d3e..86e8febc1f4 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -3075,7 +3075,19 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
if (init_master_info(mi,master_info_file_tmp,relay_log_info_file_tmp, 0,
thread_mask))
slave_errno=ER_MASTER_INFO;
- else if (server_id_supplied && *mi->host)
+ else if (!server_id_supplied)
+ {
+ slave_errno= ER_BAD_SLAVE; net_report= 0;
+ my_message(slave_errno, "Misconfigured slave: server_id was not set; Fix in config file",
+ MYF(0));
+ }
+ else if (!*mi->host)
+ {
+ slave_errno= ER_BAD_SLAVE; net_report= 0;
+ my_message(slave_errno, "Misconfigured slave: MASTER_HOST was not set; Fix in config file or with CHANGE MASTER TO",
+ MYF(0));
+ }
+ else
{
/*
If we will start SQL thread we will care about UNTIL options If
@@ -3169,8 +3181,6 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
relay_log_info_file_tmp,
thread_mask);
}
- else
- slave_errno = ER_BAD_SLAVE;
}
else
{
@@ -3519,7 +3529,8 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
*master_info_added= true;
}
if (global_system_variables.log_warnings > 1)
- sql_print_information("Master: '%.*s' Master_info_file: '%s' "
+ sql_print_information("Master connection name: '%.*s' "
+ "Master_info_file: '%s' "
"Relay_info_file: '%s'",
(int) mi->connection_name.length,
mi->connection_name.str,
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index fff0dc162c6..1949163c87a 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -15997,6 +15997,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::FIELD_ITEM:
case Item::DEFAULT_VALUE_ITEM:
case Item::INSERT_VALUE_ITEM:
+ case Item::TRIGGER_FIELD_ITEM:
{
Item_field *field= (Item_field*) item;
bool orig_modify= modify_item;
@@ -18501,6 +18502,10 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
if (return_tab < join->return_tab)
join->return_tab= return_tab;
+ /* check for errors evaluating the condition */
+ if (join->thd->is_error())
+ DBUG_RETURN(NESTED_LOOP_ERROR);
+
if (join->return_tab < join_tab)
DBUG_RETURN(NESTED_LOOP_OK);
/*
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index bcc799dce7e..10d8ed23a46 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -7988,20 +7988,13 @@ bool get_schema_tables_result(JOIN *join,
if (table_list->schema_table && thd->fill_information_schema_tables())
{
/*
- Note, currently I_S tables are filled once per query.
- This needs to be changed if if make_cond_for_info_schema()
- will preserve outer fields (and thus I_S content will depend on
- the outer subquery) - in this new case I_S tables will need to
- be re-populated here.
-
- And in that case, get_all_tables() might be called O(N^2) times
- (in self-join of TABLES, for example) and it will allocate
- table names on THD::mem_root O(N^2) times. To fix it, get_all_tables
- needs to be fixed to use a local memroot, that is reset or destroyed
- between get_all_tables invocations. Or fixed not to allocate
- table names on THD::memroot if these names don't satisfy lookup_field
+ I_S tables only need to be re-populated if make_cond_for_info_schema()
+ preserves outer fields
*/
- const bool is_subselect= false;
+ bool is_subselect= &lex->unit != lex->current_select->master_unit() &&
+ lex->current_select->master_unit()->item &&
+ tab->select_cond &&
+ tab->select_cond->used_tables() & OUTER_REF_TABLE_BIT;
/* A value of 0 indicates a dummy implementation */
if (table_list->schema_table->fill_table == 0)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 9b05cab6a10..bd2adc3220d 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -11682,9 +11682,19 @@ opt_procedure_clause:
if (add_proc_to_list(lex->thd, item))
MYSQL_YYABORT;
Lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
+
+ /*
+ PROCEDURE CLAUSE cannot handle subquery as one of its parameter,
+ so set expr_allows_subselect as false to disallow any subqueries
+ further. Reset expr_allows_subselect back to true once the
+ parameters are reduced.
+ */
+ Lex->expr_allows_subselect= false;
}
'(' procedure_list ')'
{
+ /* Subqueries are allowed from now.*/
+ Lex->expr_allows_subselect= true;
$$= true;
}
;
diff --git a/sql/threadpool_unix.cc b/sql/threadpool_unix.cc
index 68c032fb67b..e720e43498a 100644
--- a/sql/threadpool_unix.cc
+++ b/sql/threadpool_unix.cc
@@ -1634,7 +1634,7 @@ int tp_get_idle_thread_count()
Delay in microseconds, after which "pool blocked" message is printed.
(30 sec == 30 Mio usec)
*/
-#define BLOCK_MSG_DELAY 30*1000000
+#define BLOCK_MSG_DELAY (30*1000000)
#define MAX_THREADS_REACHED_MSG \
"Threadpool could not create additional thread to handle queries, because the \
diff --git a/sql/unireg.h b/sql/unireg.h
index 7599003566c..10751b6ec93 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -110,36 +110,36 @@
The flag means that we need to process tables only to get necessary data.
Views are not processed.
*/
-#define OPEN_TABLE_ONLY OPEN_FRM_FILE_ONLY*2
+#define OPEN_TABLE_ONLY (OPEN_FRM_FILE_ONLY*2)
/**
This flag is used in function get_all_tables() which fills
I_S tables with data which are retrieved from frm files and storage engine
The flag means that we need to process views only to get necessary data.
Tables are not processed.
*/
-#define OPEN_VIEW_ONLY OPEN_TABLE_ONLY*2
+#define OPEN_VIEW_ONLY (OPEN_TABLE_ONLY*2)
/**
This flag is used in function get_all_tables() which fills
I_S tables with data which are retrieved from frm files and storage engine.
The flag means that we need to open a view using
open_normal_and_derived_tables() function.
*/
-#define OPEN_VIEW_FULL OPEN_VIEW_ONLY*2
+#define OPEN_VIEW_FULL (OPEN_VIEW_ONLY*2)
/**
This flag is used in function get_all_tables() which fills
I_S tables with data which are retrieved from frm files and storage engine.
The flag means that I_S table uses optimization algorithm.
*/
-#define OPTIMIZE_I_S_TABLE OPEN_VIEW_FULL*2
+#define OPTIMIZE_I_S_TABLE (OPEN_VIEW_FULL*2)
/**
This flag is used to instruct tdc_open_view() to check metadata version.
*/
-#define CHECK_METADATA_VERSION OPEN_TRIGGER_ONLY*2
+#define CHECK_METADATA_VERSION (OPEN_TRIGGER_ONLY*2)
/*
The flag means that we need to process trigger files only.
*/
-#define OPEN_TRIGGER_ONLY OPTIMIZE_I_S_TABLE*2
+#define OPEN_TRIGGER_ONLY (OPTIMIZE_I_S_TABLE*2)
#define SC_INFO_LENGTH 4 /* Form format constant */
#define TE_INFO_LENGTH 3