summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2018-02-06 14:50:50 +0100
committerSergei Golubchik <serg@mariadb.org>2018-02-06 14:50:50 +0100
commit4771ae4b22d2bdef0aafc563570c71d4636a2493 (patch)
treed115bd7c68b1e6feab68ff6fcd547e0c86c79296 /sql
parent60f51af755ea9d07c20a596ba21de184816fa265 (diff)
parent0c25e58db6b045df92c209d396031cac5b528bbf (diff)
downloadmariadb-git-4771ae4b22d2bdef0aafc563570c71d4636a2493.tar.gz
Merge branch 'github/10.1' into 10.2
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt2
-rw-r--r--sql/contributors.h3
-rw-r--r--sql/field.cc4
-rw-r--r--sql/field.h2
-rw-r--r--sql/field_conv.cc6
-rw-r--r--sql/handler.cc14
-rw-r--r--sql/item.cc8
-rw-r--r--sql/item.h8
-rw-r--r--sql/item_cmpfunc.cc45
-rw-r--r--sql/item_cmpfunc.h6
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_strfunc.cc185
-rw-r--r--sql/item_strfunc.h1
-rw-r--r--sql/item_subselect.cc7
-rw-r--r--sql/item_xmlfunc.cc10
-rw-r--r--sql/item_xmlfunc.h1
-rw-r--r--sql/key.cc6
-rw-r--r--sql/log_event.cc7
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/net_serv.cc8
-rw-r--r--sql/opt_range.cc2
-rw-r--r--sql/sp.cc1
-rw-r--r--sql/sp_head.cc35
-rw-r--r--sql/sp_head.h3
-rw-r--r--sql/sql_admin.cc3
-rw-r--r--sql/sql_base.cc11
-rw-r--r--sql/sql_cache.cc20
-rw-r--r--sql/sql_class.cc10
-rw-r--r--sql/sql_class.h43
-rw-r--r--sql/sql_cte.cc2
-rw-r--r--sql/sql_cursor.cc2
-rw-r--r--sql/sql_derived.cc20
-rw-r--r--sql/sql_explain.h6
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_join_cache.cc2
-rw-r--r--sql/sql_lex.cc4
-rw-r--r--sql/sql_lex.h14
-rw-r--r--sql/sql_lifo_buffer.h4
-rw-r--r--sql/sql_list.h4
-rw-r--r--sql/sql_parse.cc9
-rw-r--r--sql/sql_partition.cc10
-rw-r--r--sql/sql_plugin.cc5
-rw-r--r--sql/sql_prepare.cc21
-rw-r--r--sql/sql_select.cc77
-rw-r--r--sql/sql_select.h4
-rw-r--r--sql/sql_show.cc2
-rw-r--r--sql/sql_string.h2
-rw-r--r--sql/sql_table.cc11
-rw-r--r--sql/sql_trigger.cc7
-rw-r--r--sql/sql_union.cc16
-rw-r--r--sql/sql_view.cc7
-rw-r--r--sql/table.cc8
-rw-r--r--sql/transaction.cc12
-rw-r--r--sql/unireg.cc15
-rw-r--r--sql/wsrep_sst.cc19
-rw-r--r--sql/wsrep_sst.h3
56 files changed, 435 insertions, 308 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index d929f4c047f..4d6214e1c32 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (c) 2006, 2014, Oracle and/or its affiliates.
-# Copyright (c) 2010, 2016, MariaDB Corporation
+# Copyright (c) 2010, 2018, MariaDB Corporation
#
# 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/contributors.h b/sql/contributors.h
index 88a4a088acf..7369dcd141d 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -38,8 +38,9 @@ struct show_table_contributors_st {
struct show_table_contributors_st show_table_contributors[]= {
/* MariaDB foundation sponsors, in contribution, size , time order */
{"Booking.com", "https://www.booking.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"},
- {"Alibaba Cloud", "https://intl.aliyun.com", "Platinum Sponsor of the MariaDB Foundation"},
+ {"Alibaba Cloud", "https://www.alibabacloud.com/", "Platinum Sponsor of the MariaDB Foundation"},
{"Tencent Cloud", "https://cloud.tencent.com", "Platinum Sponsor of the MariaDB Foundation"},
+ {"Microsoft", "https://microsoft.com/", "Platinum Sponsor of the MariaDB Foundation"},
{"MariaDB Corporation", "https://mariadb.com", "Founding member, Gold Sponsor of the MariaDB Foundation"},
{"Visma", "https://visma.com", "Gold Sponsor of the MariaDB Foundation"},
{"DBS", "https://dbs.com", "Gold Sponsor of the MariaDB Foundation"},
diff --git a/sql/field.cc b/sql/field.cc
index 61045cdacc0..a635b344a31 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2190,7 +2190,7 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
{
uint store_length;
copy->str= ptr;
- copy->length= pack_length();
+ copy->length= pack_length_in_rec();
copy->field= this;
if (flags & BLOB_FLAG)
{
@@ -9435,7 +9435,7 @@ int Field_bit::key_cmp(const uchar *str, uint length)
str++;
length--;
}
- return memcmp(ptr, str, length);
+ return memcmp(ptr, str, bytes_in_rec);
}
diff --git a/sql/field.h b/sql/field.h
index aeef0fa0a65..b2ef3839846 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -706,7 +706,7 @@ public:
{ return alloc_root(mem_root, size); }
static void *operator new(size_t size) throw ()
{ return thd_alloc(current_thd, size); }
- static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); }
+ static void operator delete(void *ptr_arg, size_t size) { TRASH_FREE(ptr_arg, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root)
{ DBUG_ASSERT(0); }
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index c3ad0c878b5..48c448aa57f 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -607,7 +607,7 @@ void Copy_field::set(uchar *to,Field *from)
{
from_ptr=from->ptr;
to_ptr=to;
- from_length=from->pack_length();
+ from_length=from->pack_length_in_rec();
if (from->maybe_null())
{
from_null_ptr=from->null_ptr;
@@ -655,9 +655,9 @@ void Copy_field::set(Field *to,Field *from,bool save)
from_field=from;
to_field=to;
from_ptr=from->ptr;
- from_length=from->pack_length();
+ from_length=from->pack_length_in_rec();
to_ptr= to->ptr;
- to_length=to_field->pack_length();
+ to_length=to_field->pack_length_in_rec();
// set up null handling
from_null_ptr=to_null_ptr=0;
diff --git a/sql/handler.cc b/sql/handler.cc
index 7eed722a971..0e72e0276fa 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -3324,9 +3324,11 @@ void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag)
if (key == NULL)
{
- /* Key is unknown */
- str.copy("", 0, system_charset_info);
- my_printf_error(ER_DUP_ENTRY, msg, errflag, str.c_ptr(), "*UNKNOWN*");
+ /*
+ Key is unknown. Should only happen if storage engine reports wrong
+ duplicate key number.
+ */
+ my_printf_error(ER_DUP_ENTRY, msg, errflag, "", "*UNKNOWN*");
}
else
{
@@ -3426,11 +3428,9 @@ void handler::print_error(int error, myf errflag)
if (table)
{
uint key_nr=get_dup_key(error);
- if ((int) key_nr >= 0)
+ if ((int) key_nr >= 0 && key_nr < table->s->keys)
{
- print_keydup_error(table,
- key_nr == MAX_KEY ? NULL : &table->key_info[key_nr],
- errflag);
+ print_keydup_error(table, &table->key_info[key_nr], errflag);
DBUG_VOID_RETURN;
}
}
diff --git a/sql/item.cc b/sql/item.cc
index 7b4ab6debd0..a46c17a0dbb 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2010, 2017, MariaDB Corporation
+ Copyright (c) 2010, 2018, MariaDB Corporation
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
@@ -9079,7 +9079,7 @@ bool Item_ignore_value::send(Protocol *protocol, String *buffer)
bool Item_insert_value::eq(const Item *item, bool binary_cmp) const
{
return item->type() == INSERT_VALUE_ITEM &&
- ((Item_default_value *)item)->arg->eq(arg, binary_cmp);
+ ((Item_insert_value *)item)->arg->eq(arg, binary_cmp);
}
@@ -10704,11 +10704,11 @@ const char *dbug_print_item(Item *item)
ulonglong save_option_bits= thd->variables.option_bits;
thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
- item->print(&str ,QT_EXPLAIN);
+ item->print(&str, QT_EXPLAIN);
thd->variables.option_bits= save_option_bits;
- if (str.c_ptr() == buf)
+ if (str.c_ptr_safe() == buf)
return buf;
else
return "Couldn't fit into buffer";
diff --git a/sql/item.h b/sql/item.h
index 7ff9749bf9f..727185a1deb 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -2,7 +2,7 @@
#define SQL_ITEM_INCLUDED
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB
+ Copyright (c) 2009, 2018, MariaDB Corporation
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
@@ -55,7 +55,11 @@ struct st_value
C_MODE_END
+#ifdef DBUG_OFF
+static inline const char *dbug_print_item(Item *item) { return NULL; }
+#else
const char *dbug_print_item(Item *item);
+#endif
class Protocol;
struct TABLE_LIST;
@@ -661,7 +665,7 @@ class Item: public Value_source,
public:
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
{ return alloc_root(mem_root, size); }
- static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
+ static void operator delete(void *ptr,size_t size) { TRASH_FREE(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM,
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 20afcdc3910..edaf6e87621 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1259,6 +1259,7 @@ bool Item_in_optimizer::is_top_level_item()
void Item_in_optimizer::fix_after_pullout(st_select_lex *new_parent,
Item **ref, bool merge)
{
+ DBUG_ASSERT(fixed);
/* This will re-calculate attributes of our Item_in_subselect: */
Item_bool_func::fix_after_pullout(new_parent, ref, merge);
@@ -1282,6 +1283,33 @@ bool Item_in_optimizer::eval_not_null_tables(void *opt_arg)
}
+void Item_in_optimizer::print(String *str, enum_query_type query_type)
+{
+ restore_first_argument();
+ Item_func::print(str, query_type);
+}
+
+
+/**
+ "Restore" first argument before fix_fields() call (after it is harmless).
+
+ @Note: Main pointer to left part of IN/ALL/ANY subselect is subselect's
+ lest_expr (see Item_in_optimizer::fix_left) so changes made during
+ fix_fields will be rolled back there which can make
+ Item_in_optimizer::args[0] unusable on second execution before fix_left()
+ call. This call fix the pointer.
+*/
+
+void Item_in_optimizer::restore_first_argument()
+{
+ if (args[1]->type() == Item::SUBSELECT_ITEM &&
+ ((Item_subselect *)args[1])->is_in_predicate())
+ {
+ args[0]= ((Item_in_subselect *)args[1])->left_expr;
+ }
+}
+
+
bool Item_in_optimizer::fix_left(THD *thd)
{
DBUG_ENTER("Item_in_optimizer::fix_left");
@@ -1455,6 +1483,7 @@ bool Item_in_optimizer::invisible_mode()
Item *Item_in_optimizer::expr_cache_insert_transformer(THD *thd, uchar *unused)
{
DBUG_ENTER("Item_in_optimizer::expr_cache_insert_transformer");
+ DBUG_ASSERT(fixed);
if (invisible_mode())
DBUG_RETURN(this);
@@ -1479,6 +1508,7 @@ Item *Item_in_optimizer::expr_cache_insert_transformer(THD *thd, uchar *unused)
void Item_in_optimizer::get_cache_parameters(List<Item> &parameters)
{
+ DBUG_ASSERT(fixed);
/* Add left expression to the list of the parameters of the subquery */
if (!invisible_mode())
{
@@ -1716,6 +1746,7 @@ Item *Item_in_optimizer::transform(THD *thd, Item_transformer transformer,
{
Item *new_item;
+ DBUG_ASSERT(fixed);
DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
DBUG_ASSERT(arg_count == 2);
@@ -1767,6 +1798,7 @@ Item *Item_in_optimizer::transform(THD *thd, Item_transformer transformer,
bool Item_in_optimizer::is_expensive_processor(void *arg)
{
+ DBUG_ASSERT(fixed);
return args[0]->is_expensive_processor(arg) ||
args[1]->is_expensive_processor(arg);
}
@@ -1774,6 +1806,7 @@ bool Item_in_optimizer::is_expensive_processor(void *arg)
bool Item_in_optimizer::is_expensive()
{
+ DBUG_ASSERT(fixed);
return args[0]->is_expensive() || args[1]->is_expensive();
}
@@ -2817,7 +2850,9 @@ void Item_func_nullif::print(String *str, enum_query_type query_type)
Therefore, after equal field propagation args[0] and args[2] can point
to different items.
*/
- if ((query_type & QT_ITEM_ORIGINAL_FUNC_NULLIF) || args[0] == args[2])
+ if ((query_type & QT_ITEM_ORIGINAL_FUNC_NULLIF) ||
+ (arg_count == 2) ||
+ (args[0] == args[2]))
{
/*
If QT_ITEM_ORIGINAL_FUNC_NULLIF is requested,
@@ -2835,10 +2870,14 @@ void Item_func_nullif::print(String *str, enum_query_type query_type)
- one "a" for comparison
- another "a" for the returned value!
*/
- DBUG_ASSERT(args[0] == args[2] || current_thd->lex->context_analysis_only);
+ DBUG_ASSERT(arg_count == 2 ||
+ args[0] == args[2] || current_thd->lex->context_analysis_only);
str->append(func_name());
str->append('(');
- args[2]->print(str, query_type);
+ if (arg_count == 2)
+ args[0]->print(str, query_type);
+ else
+ args[2]->print(str, query_type);
str->append(',');
args[1]->print(str, query_type);
str->append(')');
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index d6acdb4bad4..1eb07c5040a 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -362,6 +362,8 @@ public:
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
bool invisible_mode();
void reset_cache() { cache= NULL; }
+ virtual void print(String *str, enum_query_type query_type);
+ void restore_first_argument();
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_in_optimizer>(thd, mem_root, this); }
};
@@ -1784,9 +1786,9 @@ public:
bool arg_is_datetime_notnull_field()
{
Item **args= arguments();
- if (args[0]->type() == Item::FIELD_ITEM)
+ if (args[0]->real_item()->type() == Item::FIELD_ITEM)
{
- Field *field=((Item_field*) args[0])->field;
+ Field *field=((Item_field*) args[0]->real_item())->field;
if (((field->type() == MYSQL_TYPE_DATE) ||
(field->type() == MYSQL_TYPE_DATETIME)) &&
diff --git a/sql/item_func.cc b/sql/item_func.cc
index de740cbcece..a4952742d94 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -552,6 +552,7 @@ my_decimal *Item_real_func::val_decimal(my_decimal *decimal_value)
}
+#ifdef HAVE_DLOPEN
void Item_udf_func::fix_num_length_and_dec()
{
uint fl_length= 0;
@@ -568,6 +569,7 @@ void Item_udf_func::fix_num_length_and_dec()
max_length= float_length(NOT_FIXED_DEC);
}
}
+#endif
/**
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 51f66ce3193..b2317caf61e 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2017, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB
+ Copyright (c) 2009, 2018, MariaDB Corporation
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
@@ -202,9 +202,9 @@ String *Item_func_sha2::val_str_ascii(String *str)
const char *input_ptr;
size_t input_len;
+ input_string= args[0]->val_str(str);
str->set_charset(&my_charset_bin);
- input_string= args[0]->val_str(str);
if (input_string == NULL)
{
null_value= TRUE;
@@ -545,139 +545,84 @@ String *Item_func_decode_histogram::val_str(String *str)
///////////////////////////////////////////////////////////////////////////////
+/*
+ Realloc the result buffer.
+ NOTE: We should be prudent in the initial allocation unit -- the
+ size of the arguments is a function of data distribution, which
+ can be any. Instead of overcommitting at the first row, we grow
+ the allocated amount by the factor of 2. This ensures that no
+ more than 25% of memory will be overcommitted on average.
+
+ @param IN/OUT str - the result string
+ @param IN length - new total space required in "str"
+ @retval false - on success
+ @retval true - on error
+*/
+
+bool Item_func_concat::realloc_result(String *str, uint length) const
+{
+ if (str->alloced_length() >= length)
+ return false; // Alloced space is big enough, nothing to do.
+
+ if (str->alloced_length() == 0)
+ return str->alloc(length);
+
+ /*
+ Item_func_concat::val_str() makes sure the result length does not grow
+ higher than max_allowed_packet. So "length" is limited to 1G here.
+ We can't say anything about the current value of str->alloced_length(),
+ as str was initially set by args[0]->val_str(str).
+ So multiplication by 2 can overflow, if args[0] for some reasons
+ did not limit the result to max_alloced_packet. But it's not harmful,
+ "str" will be realloced exactly to "length" bytes in case of overflow.
+ */
+ uint new_length= MY_MAX(str->alloced_length() * 2, length);
+ return str->realloc(new_length);
+}
+
+
/**
Concatenate args with the following premises:
If only one arg (which is ok), return value of arg;
- Don't reallocate val_str() if not absolute necessary.
*/
String *Item_func_concat::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res,*res2,*use_as_buff;
- uint i;
- bool is_const= 0;
+ THD *thd= current_thd;
+ String *res;
null_value=0;
- if (!(res=args[0]->val_str(str)))
+ if (!(res= args[0]->val_str(str)))
goto null;
- use_as_buff= &tmp_value;
- is_const= args[0]->const_item();
- for (i=1 ; i < arg_count ; i++)
- {
- if (res->length() == 0)
- {
- if (!(res=args[i]->val_str(str)))
- goto null;
- /*
- CONCAT accumulates its result in the result of its the first
- non-empty argument. Because of this we need is_const to be
- evaluated only for it.
- */
- is_const= args[i]->const_item();
- }
- else
- {
- if (!(res2=args[i]->val_str(use_as_buff)))
- goto null;
- if (res2->length() == 0)
- continue;
- if (res->length()+res2->length() >
- current_thd->variables.max_allowed_packet)
- {
- THD *thd= current_thd;
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WARN_ALLOWED_PACKET_OVERFLOWED,
- ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED),
- func_name(),
- thd->variables.max_allowed_packet);
- goto null;
- }
- if (!is_const && res->alloced_length() >= res->length()+res2->length())
- { // Use old buffer
- res->append(*res2);
- }
- else if (str->alloced_length() >= res->length()+res2->length())
- {
- if (str->ptr() == res2->ptr())
- str->replace(0,0,*res);
- else
- {
- str->copy(*res);
- str->append(*res2);
- }
- res= str;
- use_as_buff= &tmp_value;
- }
- else if (res == &tmp_value)
- {
- if (res->append(*res2)) // Must be a blob
- goto null;
- }
- else if (res2 == &tmp_value)
- { // This can happend only 1 time
- if (tmp_value.replace(0,0,*res))
- goto null;
- res= &tmp_value;
- use_as_buff=str; // Put next arg here
- }
- else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() &&
- res2->ptr() <= tmp_value.ptr() + tmp_value.alloced_length())
- {
- /*
- This happens really seldom:
- In this case res2 is sub string of tmp_value. We will
- now work in place in tmp_value to set it to res | res2
- */
- /* Chop the last characters in tmp_value that isn't in res2 */
- tmp_value.length((uint32) (res2->ptr() - tmp_value.ptr()) +
- res2->length());
- /* Place res2 at start of tmp_value, remove chars before res2 */
- if (tmp_value.replace(0,(uint32) (res2->ptr() - tmp_value.ptr()),
- *res))
- goto null;
- res= &tmp_value;
- use_as_buff=str; // Put next arg here
- }
- else
- { // Two big const strings
- /*
- NOTE: We should be prudent in the initial allocation unit -- the
- size of the arguments is a function of data distribution, which
- can be any. Instead of overcommitting at the first row, we grow
- the allocated amount by the factor of 2. This ensures that no
- more than 25% of memory will be overcommitted on average.
- */
-
- uint concat_len= res->length() + res2->length();
-
- if (tmp_value.alloced_length() < concat_len)
- {
- if (tmp_value.alloced_length() == 0)
- {
- if (tmp_value.alloc(concat_len))
- goto null;
- }
- else
- {
- uint new_len = MY_MAX(tmp_value.alloced_length() * 2, concat_len);
- if (tmp_value.realloc(new_len))
- goto null;
- }
- }
+ if (res != str)
+ str->copy(res->ptr(), res->length(), res->charset());
- if (tmp_value.copy(*res) || tmp_value.append(*res2))
- goto null;
-
- res= &tmp_value;
- use_as_buff=str;
- }
- is_const= 0;
+ for (uint i= 1 ; i < arg_count ; i++)
+ {
+ uint concat_len;
+ if (!(res= args[i]->val_str(&tmp_value)))
+ goto null;
+ if (res->length() == 0)
+ continue;
+ if ((concat_len= str->length() + res->length()) >
+ thd->variables.max_allowed_packet)
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_ALLOWED_PACKET_OVERFLOWED,
+ ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(),
+ thd->variables.max_allowed_packet);
+ goto null;
}
+ DBUG_ASSERT(!res->uses_buffer_owned_by(str));
+ DBUG_ASSERT(!str->uses_buffer_owned_by(res));
+ if (realloc_result(str, concat_len) || str->append(*res))
+ goto null;
}
- res->set_charset(collation.collation);
- return res;
+
+ str->set_charset(collation.collation);
+ return str;
null:
null_value=1;
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index e851ab59b6a..3723f4eb5f4 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -245,6 +245,7 @@ public:
class Item_func_concat :public Item_str_func
{
String tmp_value;
+ bool realloc_result(String *str, uint length) const;
public:
Item_func_concat(THD *thd, List<Item> &list): Item_str_func(thd, list) {}
Item_func_concat(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 74f11ca6e41..d36c34797dc 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -2139,7 +2139,10 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
}
else
{
- Item *item= (Item*) select_lex->item_list.head()->real_item();
+ Item *item= (Item*) select_lex->item_list.head();
+ if (item->type() != REF_ITEM ||
+ ((Item_ref*)item)->ref_type() != Item_ref::VIEW_REF)
+ item= item->real_item();
if (select_lex->table_list.elements)
{
@@ -5510,7 +5513,7 @@ int subselect_hash_sj_engine::exec()
if (has_covering_null_row)
{
- DBUG_ASSERT(count_partial_match_columns = field_count);
+ DBUG_ASSERT(count_partial_match_columns == field_count);
count_pm_keys= 0;
}
else if (has_covering_null_columns)
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 57b1807d78c..af62a94afd0 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -2718,7 +2718,7 @@ void Item_xml_str_func::fix_length_and_dec()
bool Item_xml_str_func::fix_fields(THD *thd, Item **ref)
{
- String *xp, tmp;
+ String *xp;
MY_XPATH xpath;
int rc;
@@ -2746,7 +2746,13 @@ bool Item_xml_str_func::fix_fields(THD *thd, Item **ref)
return true;
}
- if (!(xp= args[1]->val_str(&tmp)))
+ /*
+ Get the XPath query text from args[1] and cache it in m_xpath_query.
+ Its fragments will be referenced by items created during my_xpath_parse(),
+ e.g. by Item_nodeset_func_axisbyname::node_name.
+ */
+ if (!(xp= args[1]->val_str(&m_xpath_query)) ||
+ (xp != &m_xpath_query && m_xpath_query.copy(*xp)))
return false; // Will return NULL
my_xpath_init(&xpath);
xpath.thd= thd;
diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h
index 3c071b897e2..d281e076ec8 100644
--- a/sql/item_xmlfunc.h
+++ b/sql/item_xmlfunc.h
@@ -62,6 +62,7 @@ protected:
return parse(res, cache);
}
};
+ String m_xpath_query; // XPath query text
Item *nodeset_func;
XML xml;
bool get_xml(XML *xml_arg, bool cache= false)
diff --git a/sql/key.cc b/sql/key.cc
index 0040647b5c7..4453a97dee4 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -63,7 +63,8 @@ int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field,
i < (int) key_count ;
i++, key_info++)
{
- if (key_info->key_part[0].offset == fieldpos)
+ if (key_info->key_part[0].offset == fieldpos &&
+ key_info->key_part[0].field->type() != MYSQL_TYPE_BIT)
{ /* Found key. Calc keylength */
*key_length= *keypart= 0;
return i; /* Use this key */
@@ -82,7 +83,8 @@ int find_ref_key(KEY *key, uint key_count, uchar *record, Field *field,
j < key_info->user_defined_key_parts ;
j++, key_part++)
{
- if (key_part->offset == fieldpos)
+ if (key_part->offset == fieldpos &&
+ key_part->field->type() != MYSQL_TYPE_BIT)
{
*keypart= j;
return i; /* Use this key */
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 30f1e88b86c..55e5e49f5bd 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -4988,8 +4988,13 @@ bool test_if_equal_repl_errors(int expected_error, int actual_error)
return 1;
switch (expected_error) {
case ER_DUP_ENTRY:
+ case ER_DUP_ENTRY_WITH_KEY_NAME:
+ case ER_DUP_KEY:
case ER_AUTOINC_READ_FAILED:
- return (actual_error == ER_AUTOINC_READ_FAILED ||
+ return (actual_error == ER_DUP_ENTRY ||
+ actual_error == ER_DUP_ENTRY_WITH_KEY_NAME ||
+ actual_error == ER_DUP_KEY ||
+ actual_error == ER_AUTOINC_READ_FAILED ||
actual_error == HA_ERR_AUTOINC_ERANGE);
case ER_UNKNOWN_TABLE:
return actual_error == ER_IT_IS_A_VIEW;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 6b9069adc8f..ab360a5bf6c 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4204,7 +4204,7 @@ static int init_common_variables()
/* TODO: remove this when my_time_t is 64 bit compatible */
if (!IS_TIME_T_VALID_FOR_TIMESTAMP(server_start_time))
{
- sql_print_error("This MySQL server doesn't support dates later then 2038");
+ sql_print_error("This MySQL server doesn't support dates later than 2038");
exit(1);
}
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index d9d35c5ed3f..7b988fd369b 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2012, 2017, MariaDB Corporation
+ Copyright (c) 2012, 2018, MariaDB Corporation.
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
@@ -58,6 +58,7 @@
#ifdef EXTRA_DEBUG
#define EXTRA_DEBUG_fprintf fprintf
#define EXTRA_DEBUG_fflush fflush
+#define EXTRA_DEBUG_ASSERT DBUG_ASSERT
#else
static void inline EXTRA_DEBUG_fprintf(...) {}
#ifndef MYSQL_SERVER
@@ -70,6 +71,9 @@ static int inline EXTRA_DEBUG_fflush(...) { return 0; }
static void inline MYSQL_SERVER_my_error(...) {}
#endif
+#ifndef EXTRA_DEBUG_ASSERT
+# define EXTRA_DEBUG_ASSERT(X) do {} while(0)
+#endif
/*
The following handles the differences when this is linked between the
@@ -1085,7 +1089,7 @@ packets_out_of_order:
("Packets out of order (Found: %d, expected %u)",
(int) net->buff[net->where_b + 3],
net->pkt_nr));
- DBUG_ASSERT(0);
+ EXTRA_DEBUG_ASSERT(0);
/*
We don't make noise server side, since the client is expected
to break the protocol for e.g. --send LOAD DATA .. LOCAL where
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index cc5746925a2..b011c01a948 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -2070,7 +2070,7 @@ public:
/* Table read plans are allocated on MEM_ROOT and are never deleted */
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, (uint) size); }
- static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
+ static void operator delete(void *ptr,size_t size) { TRASH_FREE(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) { /* Never called */ }
virtual ~TABLE_READ_PLAN() {} /* Remove gcc warning */
diff --git a/sql/sp.cc b/sql/sp.cc
index ef4d0996b78..89797ff400a 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -760,7 +760,6 @@ static sp_head *sp_compile(THD *thd, String *defstr, sql_mode_t sql_mode,
else
{
sp= thd->lex->sphead;
- sp->set_select_number(thd->select_number);
}
thd->pop_internal_handler();
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index eca72f4d643..081d8cb9c23 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -578,7 +578,7 @@ sp_head::sp_head()
m_flags(0),
m_sp_cache_version(0),
m_creation_ctx(0),
- unsafe_flags(0), m_select_number(1),
+ unsafe_flags(0),
m_recursion_level(0),
m_next_cached_sp(0),
m_cont_level(0)
@@ -822,7 +822,7 @@ sp_head::~sp_head()
thd->lex->sphead= NULL;
lex_end(thd->lex);
delete thd->lex;
- thd->lex= lex;
+ thd->lex= thd->stmt_lex= lex;
}
my_hash_free(&m_sptabs);
@@ -1129,7 +1129,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
backup_arena;
query_id_t old_query_id;
TABLE *old_derived_tables;
- LEX *old_lex;
+ LEX *old_lex, *old_stmt_lex;
Item_change_list old_change_list;
String old_packet;
uint old_server_status;
@@ -1145,19 +1145,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
if (check_stack_overrun(thd, 7 * STACK_MIN_SIZE, (uchar*)&old_packet))
DBUG_RETURN(TRUE);
- /*
- Normally the counter is not reset between parsing and first execution,
- but it is possible in case of error to have parsing on one CALL and
- first execution (where VIEW will be parsed and added). So we store the
- counter after parsing and restore it before execution just to avoid
- repeating SELECT numbers.
-
- Other problem is that it can be more SELECTs parsed in case of fixing
- error causes previous interruption of the SP. So it is save not just
- assign old value but add it.
- */
- thd->select_number+= m_select_number;
-
/* init per-instruction memroot */
init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
@@ -1246,6 +1233,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
do it in each instruction
*/
old_lex= thd->lex;
+ old_stmt_lex= thd->stmt_lex;
/*
We should also save Item tree change list to avoid rollback something
too early in the calling query.
@@ -1395,6 +1383,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
DBUG_ASSERT(thd->Item_change_list::is_empty());
old_change_list.move_elements_to(thd);
thd->lex= old_lex;
+ thd->stmt_lex= old_stmt_lex;
thd->set_query_id(old_query_id);
DBUG_ASSERT(!thd->derived_tables);
thd->derived_tables= old_derived_tables;
@@ -1493,16 +1482,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
m_recursion_level + 1));
m_first_instance->m_first_free_instance= this;
- /*
- This execution of the SP was aborted with an error (e.g. "Table not
- found"). However it might still have consumed some numbers from the
- thd->select_number counter. The next sp->exec() call must not use the
- consumed numbers, so we remember the first free number (We know that
- nobody will use it as this execution has stopped with an error).
- */
- if (err_status)
- set_select_number(thd->select_number);
-
DBUG_RETURN(err_status);
}
@@ -2241,7 +2220,7 @@ sp_head::reset_lex(THD *thd)
if (sublex == 0)
DBUG_RETURN(TRUE);
- thd->lex= sublex;
+ thd->lex= thd->stmt_lex= sublex;
(void)m_lex.push_front(oldlex);
/* Reset most stuff. */
@@ -2985,7 +2964,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
We should not save old value since it is saved/restored in
sp_head::execute() when we are entering/leaving routine.
*/
- thd->lex= m_lex;
+ thd->lex= thd->stmt_lex= m_lex;
thd->set_query_id(next_query_id());
diff --git a/sql/sp_head.h b/sql/sp_head.h
index ed9fef5116f..9f1745f2aab 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -229,7 +229,6 @@ private:
*/
uint32 unsafe_flags;
- uint m_select_number;
public:
inline Stored_program_creation_ctx *get_creation_ctx()
{
@@ -518,8 +517,6 @@ public:
sp_pcontext *get_parse_context() { return m_pcont; }
- void set_select_number(uint num) { m_select_number= num; }
-
private:
MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 5222381270a..6474213cb9f 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -698,8 +698,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
if (lock_type == TL_WRITE && !table->table->s->tmp_table &&
table->mdl_request.type > MDL_SHARED_WRITE)
{
- if (wait_while_table_is_used(thd, table->table,
- HA_EXTRA_PREPARE_FOR_RENAME))
+ if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED))
goto err;
DEBUG_SYNC(thd, "after_admin_flush");
/* Flush entries in the query cache involving this table. */
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 3f5af2985db..eb92ed631df 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -8414,7 +8414,16 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
DBUG_PRINT("info",("Performing FULLTEXT search"));
while ((ifm=li++))
- ifm->init_search(thd, no_order);
+#if MYSQL_VERSION_ID < 100213
+ if (unlikely(!ifm->fixed))
+ /*
+ it mean that clause where was FT function was removed, so we have
+ to remove the function from the list.
+ */
+ li.remove();
+ else
+#endif
+ ifm->init_search(thd, no_order);
}
return 0;
}
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index b5c0e457a36..17f896374a4 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1188,7 +1188,11 @@ void Query_cache::end_of_result(THD *thd)
#endif
if (try_lock(thd, Query_cache::WAIT))
+ {
+ if (is_disabled())
+ query_cache_tls->first_query_block= NULL; // do not try again with QC
DBUG_VOID_RETURN;
+ }
query_block= query_cache_tls->first_query_block;
if (query_block)
@@ -1565,6 +1569,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
unlock();
+ DEBUG_SYNC(thd, "wait_in_query_cache_store_query");
+
// init_n_lock make query block locked
BLOCK_UNLOCK_WR(query_block);
}
@@ -2570,6 +2576,7 @@ void Query_cache::init()
*/
if (global_system_variables.query_cache_type == 0)
{
+ m_cache_status= DISABLE_REQUEST;
free_cache();
m_cache_status= DISABLED;
}
@@ -2778,13 +2785,17 @@ void Query_cache::make_disabled()
This function frees all resources allocated by the cache. You
have to call init_cache() before using the cache again. This function
- requires the structure_guard_mutex to be locked.
+ requires the cache to be locked (LOCKED_NO_WAIT, lock_and_suspend) or
+ disabling.
*/
void Query_cache::free_cache()
{
DBUG_ENTER("Query_cache::free_cache");
+ DBUG_ASSERT(m_cache_lock_status == LOCKED_NO_WAIT ||
+ m_cache_status == DISABLE_REQUEST);
+
/* Destroy locks */
Query_cache_block *block= queries_blocks;
if (block)
@@ -2792,6 +2803,13 @@ void Query_cache::free_cache()
do
{
Query_cache_query *query= block->query();
+ /*
+ There will not be new requests but some maybe not finished yet,
+ so wait for them by trying lock/unlock
+ */
+ BLOCK_LOCK_WR(block);
+ BLOCK_UNLOCK_WR(block);
+
mysql_rwlock_destroy(&query->lock);
block= block->next;
} while (block != queries_blocks);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 6922a7ae5df..1e07849db16 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -2661,6 +2661,9 @@ Item_change_list::check_and_register_item_tree_change(Item **place,
MEM_ROOT *runtime_memroot)
{
Item_change_record *change;
+ DBUG_ENTER("THD::check_and_register_item_tree_change");
+ DBUG_PRINT("enter", ("Register: %p (%p) <- %p (%p)",
+ *place, place, *new_value, new_value));
I_List_iterator<Item_change_record> it(change_list);
while ((change= it++))
{
@@ -2670,6 +2673,7 @@ Item_change_list::check_and_register_item_tree_change(Item **place,
if (change)
nocheck_register_item_tree_change(place, change->old_value,
runtime_memroot);
+ DBUG_VOID_RETURN;
}
@@ -2677,17 +2681,13 @@ void Item_change_list::rollback_item_tree_changes()
{
I_List_iterator<Item_change_record> it(change_list);
Item_change_record *change;
- DBUG_ENTER("rollback_item_tree_changes");
while ((change= it++))
{
- DBUG_PRINT("info", ("revert %p -> %p",
- change->old_value, (*change->place)));
*change->place= change->old_value;
}
/* We can forget about changes memory: it's allocated in runtime memroot */
change_list.empty();
- DBUG_VOID_RETURN;
}
@@ -3602,7 +3602,7 @@ void Statement::set_statement(Statement *stmt)
{
id= stmt->id;
mark_used_columns= stmt->mark_used_columns;
- lex= stmt->lex;
+ stmt_lex= lex= stmt->lex;
query_string= stmt->query_string;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 5a409ec8268..d4546a0c550 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1054,6 +1054,21 @@ public:
LEX_STRING name; /* name for named prepared statements */
LEX *lex; // parse tree descriptor
/*
+ LEX which represents current statement (conventional, SP or PS)
+
+ For example during view parsing THD::lex will point to the views LEX and
+ THD::stmt_lex will point to LEX of the statement where the view will be
+ included
+
+ Currently it is used to have always correct select numbering inside
+ statement (LEX::current_select_number) without storing and restoring a
+ global counter which was THD::select_number.
+
+ TODO: make some unified statement representation (now SP has different)
+ to store such data like LEX::current_select_number.
+ */
+ LEX *stmt_lex;
+ /*
Points to the query associated with this statement. It's const, but
we need to declare it char * because all table handlers are written
in C and need to point to it.
@@ -1206,6 +1221,29 @@ typedef struct st_xid_state {
/* Error reported by the Resource Manager (RM) to the Transaction Manager. */
uint rm_error;
XID_cache_element *xid_cache_element;
+
+ /**
+ Check that XA transaction has an uncommitted work. Report an error
+ to the user in case when there is an uncommitted work for XA transaction.
+
+ @return result of check
+ @retval false XA transaction is NOT in state IDLE, PREPARED
+ or ROLLBACK_ONLY.
+ @retval true XA transaction is in state IDLE or PREPARED
+ or ROLLBACK_ONLY.
+ */
+
+ bool check_has_uncommitted_xa() const
+ {
+ if (xa_state == XA_IDLE ||
+ xa_state == XA_PREPARED ||
+ xa_state == XA_ROLLBACK_ONLY)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ return true;
+ }
+ return false;
+ }
} XID_STATE;
void xid_cache_init(void);
@@ -2869,7 +2907,6 @@ public:
uint tmp_table, global_disable_checkpoint;
uint server_status,open_options;
enum enum_thread_type system_thread;
- uint select_number; //number of select (used for EXPLAIN)
/*
Current or next transaction isolation level.
When a connection is established, the value is taken from
@@ -3607,10 +3644,14 @@ public:
void change_item_tree(Item **place, Item *new_value)
{
+ DBUG_ENTER("THD::change_item_tree");
+ DBUG_PRINT("enter", ("Register: %p (%p) <- %p",
+ *place, place, new_value));
/* TODO: check for OOM condition here */
if (!stmt_arena->is_conventional())
nocheck_register_item_tree_change(place, *place, mem_root);
*place= new_value;
+ DBUG_VOID_RETURN;
}
/**
Make change in item tree after checking whether it needs registering
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index d12948fb624..ecb984cb2ce 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -813,7 +813,7 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
goto err;
lex_start(thd);
with_select= &lex->select_lex;
- with_select->select_number= ++thd->select_number;
+ with_select->select_number= ++thd->stmt_lex->current_select_number;
parse_status= parse_sql(thd, &parser_state, 0);
if (parse_status)
goto err;
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
index 118c6f23cb0..dbe5dd0dce9 100644
--- a/sql/sql_cursor.cc
+++ b/sql/sql_cursor.cc
@@ -211,7 +211,7 @@ void Server_side_cursor::operator delete(void *ptr, size_t size)
MEM_ROOT own_root= *cursor->mem_root;
DBUG_ENTER("Server_side_cursor::operator delete");
- TRASH(ptr, size);
+ TRASH_FREE(ptr, size);
/*
If this cursor has never been opened mem_root is empty. Otherwise
mem_root points to the memory the cursor object was allocated in.
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 3e84536673a..60827bd1772 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -369,7 +369,11 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
derived->get_unit()));
if (derived->merged)
+ {
+
+ DBUG_PRINT("info", ("Irreversibly merged: exit"));
DBUG_RETURN(FALSE);
+ }
if (dt_select->uncacheable & UNCACHEABLE_RAND)
{
@@ -745,6 +749,17 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
}
unit->derived= derived;
+
+ /*
+ Above cascade call of prepare is important for PS protocol, but after it
+ is called we can check if we really need prepare for this derived
+ */
+ if (derived->merged)
+ {
+ DBUG_PRINT("info", ("Irreversibly merged: exit"));
+ DBUG_RETURN(FALSE);
+ }
+
derived->fill_me= FALSE;
if (!(derived->derived_result= new (thd->mem_root) select_union(thd)))
@@ -886,6 +901,11 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived)
DBUG_PRINT("enter", ("Alias: '%s' Unit: %p",
(derived->alias ? derived->alias : "<NULL>"),
derived->get_unit()));
+ if (derived->merged)
+ {
+ DBUG_PRINT("info", ("Irreversibly merged: exit"));
+ DBUG_RETURN(FALSE);
+ }
if (unit->optimized)
DBUG_RETURN(FALSE);
diff --git a/sql/sql_explain.h b/sql/sql_explain.h
index a4698908755..489a23f7cda 100644
--- a/sql/sql_explain.h
+++ b/sql/sql_explain.h
@@ -207,6 +207,9 @@ public:
Explain_select(MEM_ROOT *root, bool is_analyze) :
Explain_basic_join(root),
+#ifndef DBUG_OFF
+ select_lex(NULL),
+#endif
message(NULL),
having(NULL), having_value(Item::COND_UNDEF),
using_temporary(false), using_filesort(false),
@@ -215,6 +218,9 @@ public:
{}
public:
+#ifndef DBUG_OFF
+ SELECT_LEX *select_lex;
+#endif
const char *select_type;
/*
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index a94349527bf..682f4b07ffa 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2010, 2017, MariaDB
+ Copyright (c) 2010, 2018, MariaDB Corporation
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/sql_join_cache.cc b/sql/sql_join_cache.cc
index e6ef8a4be9f..3612cb6cc32 100644
--- a/sql/sql_join_cache.cc
+++ b/sql/sql_join_cache.cc
@@ -393,7 +393,7 @@ void JOIN_CACHE::create_flag_fields()
TABLE *table= tab->table;
/* Create a field for the null bitmap from table if needed */
- if (tab->used_null_fields || tab->used_uneven_bit_fields)
+ if (tab->used_null_fields || tab->used_uneven_bit_fields)
length+= add_flag_field_to_join_cache(table->null_flags,
table->s->null_bytes,
&copy);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 69931643c7f..4c8ac42ab98 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2014, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB
+ Copyright (c) 2009, 2018, MariaDB Corporation
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
@@ -654,6 +654,7 @@ void lex_start(THD *thd)
{
LEX *lex= thd->lex;
DBUG_ENTER("lex_start");
+ DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex));
lex->thd= lex->unit.thd= thd;
@@ -665,6 +666,7 @@ void lex_start(THD *thd)
/* 'parent_lex' is used in init_query() so it must be before it. */
lex->select_lex.parent_lex= lex;
lex->select_lex.init_query();
+ lex->current_select_number= 1;
lex->curr_with_clause= 0;
lex->with_clauses_list= 0;
lex->with_clauses_list_last_next= &lex->with_clauses_list;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 27db46fa541..88462477de9 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2010, 2017, MariaDB Corporation.
+ Copyright (c) 2010, 2018, MariaDB Corporation
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
@@ -507,7 +507,7 @@ public:
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
{ return (void*) alloc_root(mem_root, (uint) size); }
- static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
+ static void operator delete(void *ptr,size_t size) { TRASH_FREE(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
// Ensures that at least all members used during cleanup() are initialized.
@@ -767,7 +767,13 @@ public:
Item *cond_pushed_into_having; /* condition pushed into the select's HAVING */
/* Saved values of the WHERE and HAVING clauses*/
Item::cond_result cond_value, having_value;
- /* point on lex in which it was created, used in view subquery detection */
+ /*
+ Point to the LEX in which it was created, used in view subquery detection.
+
+ TODO: make also st_select_lex::parent_stmt_lex (see THD::stmt_lex)
+ and use st_select_lex::parent_lex & st_select_lex::parent_stmt_lex
+ instead of global (from THD) references where it is possible.
+ */
LEX *parent_lex;
enum olap_type olap;
/* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */
@@ -2564,7 +2570,7 @@ struct LEX: public Query_tables_list
/** SELECT of CREATE VIEW statement */
LEX_STRING create_view_select;
- uint number_of_selects; // valid only for view
+ uint current_select_number; // valid for statment LEX (not view)
/** Start of 'ON table', in trigger statements. */
const char* raw_trg_on_table_name_begin;
diff --git a/sql/sql_lifo_buffer.h b/sql/sql_lifo_buffer.h
index 8fa13c66dd9..17024d15beb 100644
--- a/sql/sql_lifo_buffer.h
+++ b/sql/sql_lifo_buffer.h
@@ -84,7 +84,7 @@ public:
start= start_arg;
end= end_arg;
if (end != start)
- TRASH(start, end - start);
+ TRASH_ALLOC(start, end - start);
reset();
}
@@ -224,7 +224,7 @@ public:
{
DBUG_ASSERT(unused_end >= unused_start);
DBUG_ASSERT(end == unused_start);
- TRASH(unused_start, unused_end - unused_start);
+ TRASH_ALLOC(unused_start, unused_end - unused_start);
end= unused_end;
}
/* Return pointer to start of the memory area that is occupied by the data */
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 8f6f7337f1c..321041cf200 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -42,12 +42,12 @@ public:
{ return alloc_root(mem_root, size); }
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
{ return alloc_root(mem_root, size); }
- static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); }
+ static void operator delete(void *ptr, size_t size) { TRASH_FREE(ptr, size); }
static void operator delete(void *ptr, MEM_ROOT *mem_root)
{ /* never called */ }
static void operator delete[](void *ptr, MEM_ROOT *mem_root)
{ /* never called */ }
- static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); }
+ static void operator delete[](void *ptr, size_t size) { TRASH_FREE(ptr, size); }
#ifdef HAVE_valgrind
bool dummy_for_valgrind;
inline Sql_alloc() :dummy_for_valgrind(0) {}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 835ffeaecb3..578627f265a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -7433,7 +7433,12 @@ void THD::reset_for_next_command(bool do_clear_error)
clear_error(1);
thd->free_list= 0;
- thd->select_number= 1;
+ /*
+ We also assign thd->stmt_lex in lex_start(), but during bootstrap this
+ code is executed first.
+ */
+ thd->stmt_lex= &main_lex; thd->stmt_lex->current_select_number= 1;
+ DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex));
/*
Those two lines below are theoretically unneeded as
THD::cleanup_after_query() should take care of this already.
@@ -7550,7 +7555,7 @@ mysql_new_select(LEX *lex, bool move_down)
if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
DBUG_RETURN(1);
- select_lex->select_number= ++thd->select_number;
+ select_lex->select_number= ++thd->stmt_lex->current_select_number;
select_lex->parent_lex= lex; /* Used in init_query. */
select_lex->init_query();
select_lex->init_select();
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index fd8d23f5187..1376115e77c 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -4431,8 +4431,14 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
!thd->lex->part_info->num_columns)
thd->lex->part_info->num_columns= 1; // to make correct clone
- if ((thd->work_part_info= thd->lex->part_info) &&
- !(thd->work_part_info= thd->lex->part_info->get_clone(thd)))
+ /*
+ One of these is done in handle_if_exists_option():
+ thd->work_part_info= thd->lex->part_info;
+ or
+ thd->work_part_info= NULL;
+ */
+ if (thd->work_part_info &&
+ !(thd->work_part_info= thd->work_part_info->get_clone(thd)))
DBUG_RETURN(TRUE);
/* ALTER_ADMIN_PARTITION is handled in mysql_admin_table */
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 24f4495d37f..adf6fa4f936 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -488,6 +488,11 @@ static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl)
sizeof(struct st_plugin_dl));
DBUG_RETURN(tmp);
}
+#else
+static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *)
+{
+ return 0;
+}
#endif /* HAVE_DLOPEN */
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 16c386e5e8f..3e1dcc22acd 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -167,20 +167,6 @@ public:
uint param_count;
uint last_errno;
uint flags;
- /*
- The value of thd->select_number at the end of the PREPARE phase.
-
- The issue is: each statement execution opens VIEWs, which may cause
- select_lex objects to be created, and select_number values to be assigned.
-
- On the other hand, PREPARE assigns select_number values for triggers and
- subqueries.
-
- In order for select_number values from EXECUTE not to conflict with
- select_number values from PREPARE, we keep the number and set it at each
- execution.
- */
- uint select_number_after_prepare;
char last_error[MYSQL_ERRMSG_SIZE];
my_bool iterations;
my_bool start_param;
@@ -3848,9 +3834,9 @@ void Prepared_statement::cleanup_stmt()
DBUG_ENTER("Prepared_statement::cleanup_stmt");
DBUG_PRINT("enter",("stmt: %p", this));
thd->restore_set_statement_var();
+ thd->rollback_item_tree_changes();
cleanup_items(free_list);
thd->cleanup_after_query();
- thd->rollback_item_tree_changes();
DBUG_VOID_RETURN;
}
@@ -3935,6 +3921,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
if (! (lex= new (mem_root) st_lex_local))
DBUG_RETURN(TRUE);
+ stmt_lex= lex;
if (set_db(thd->db, thd->db_length))
DBUG_RETURN(TRUE);
@@ -4040,8 +4027,6 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
trans_rollback_implicit(thd);
thd->mdl_context.release_transactional_locks();
}
-
- select_number_after_prepare= thd->select_number;
/* Preserve CHANGE MASTER attributes */
lex_end_stage1(lex);
@@ -4178,7 +4163,6 @@ Prepared_statement::execute_loop(String *expanded_query,
*/
DBUG_ASSERT(thd->free_list == NULL);
- thd->select_number= select_number_after_prepare;
/* Check if we got an error when sending long data */
if (state == Query_arena::STMT_ERROR)
{
@@ -4321,7 +4305,6 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
#ifndef DBUG_OFF
Item *free_list_state= thd->free_list;
#endif
- thd->select_number= select_number_after_prepare;
thd->set_bulk_execution((void *)this);
/* Check if we got an error when sending long data */
if (state == Query_arena::STMT_ERROR)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index a98477d2839..4746f186fe7 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2016 Oracle and/or its affiliates.
- Copyright (c) 2009, 2016 MariaDB
+ Copyright (c) 2009, 2018 MariaDB Corporation
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
@@ -280,6 +280,9 @@ JOIN_TAB *next_depth_first_tab(JOIN* join, JOIN_TAB* tab);
static JOIN_TAB *next_breadth_first_tab(JOIN_TAB *first_top_tab,
uint n_top_tabs_count, JOIN_TAB *tab);
+static bool find_order_in_list(THD *, Ref_ptr_array, TABLE_LIST *, ORDER *,
+ List<Item> &, List<Item> &, bool, bool, bool);
+
static double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
table_map rem_tables);
void set_postjoin_aggr_write_func(JOIN_TAB *tab);
@@ -331,7 +334,7 @@ bool dbug_user_var_equals_int(THD *thd, const char *name, int value)
}
return FALSE;
}
-#endif
+#endif
/**
@@ -707,6 +710,9 @@ JOIN::prepare(TABLE_LIST *tables_init,
join_list= &select_lex->top_join_list;
union_part= unit_arg->is_union();
+ // simple check that we got usable conds
+ dbug_print_item(conds);
+
if (select_lex->handle_derived(thd->lex, DT_PREPARE))
DBUG_RETURN(1);
@@ -822,9 +828,15 @@ JOIN::prepare(TABLE_LIST *tables_init,
{
nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
thd->lex->allow_sum_func|= (nesting_map)1 << select_lex->nest_level;
- if (setup_order(thd, ref_ptrs, tables_list, fields_list,
- all_fields, select_lex->order_list.first))
- DBUG_RETURN(-1);
+ thd->where= "order clause";
+ for (ORDER *order= select_lex->order_list.first; order; order= order->next)
+ {
+ /* Don't add the order items to all fields. Just resolve them to ensure
+ the query is valid, we'll drop them immediately after. */
+ if (find_order_in_list(thd, ref_ptrs, tables_list, order,
+ fields_list, all_fields, false, false, false))
+ DBUG_RETURN(-1);
+ }
thd->lex->allow_sum_func= save_allow_sum_func;
select_lex->order_list.empty();
}
@@ -3140,8 +3152,11 @@ bool JOIN::shrink_join_buffers(JOIN_TAB *jt,
ulonglong curr_space,
ulonglong needed_space)
{
+ JOIN_TAB *tab;
JOIN_CACHE *cache;
- for (JOIN_TAB *tab= join_tab+const_tables; tab < jt; tab++)
+ for (tab= first_linear_tab(this, WITHOUT_BUSH_ROOTS, WITHOUT_CONST_TABLES);
+ tab != jt;
+ tab= next_linear_tab(this, tab, WITHOUT_BUSH_ROOTS))
{
cache= tab->cache;
if (cache)
@@ -3278,6 +3293,17 @@ void JOIN::save_explain_data(Explain_query *output, bool can_overwrite,
bool need_tmp_table, bool need_order,
bool distinct)
{
+ /*
+ If there is SELECT in this statemet with the same number it must be the
+ same SELECT
+ */
+ DBUG_ASSERT(select_lex->select_number == UINT_MAX ||
+ select_lex->select_number == INT_MAX ||
+ !output ||
+ !output->get_select(select_lex->select_number) ||
+ output->get_select(select_lex->select_number)->select_lex ==
+ select_lex);
+
if (select_lex->select_number != UINT_MAX &&
select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ &&
have_query_plan != JOIN::QEP_NOT_PRESENT_YET &&
@@ -10553,7 +10579,7 @@ void JOIN::drop_unused_derived_keys()
tmp_tbl->use_index(tab->ref.key);
if (tmp_tbl->s->keys)
{
- if (tab->ref.key >= 0)
+ if (tab->ref.key >= 0 && tab->ref.key < MAX_KEY)
tab->ref.key= 0;
else
tmp_tbl->s->keys= 0;
@@ -12375,8 +12401,8 @@ static void update_depend_map(JOIN *join)
uint i;
for (i=0 ; i < ref->key_parts ; i++,item++)
depend_map|=(*item)->used_tables();
- ref->depend_map=depend_map & ~OUTER_REF_TABLE_BIT;
depend_map&= ~OUTER_REF_TABLE_BIT;
+ ref->depend_map= depend_map;
for (JOIN_TAB **tab=join->map2table;
depend_map ;
tab++,depend_map>>=1 )
@@ -12780,7 +12806,7 @@ public:
}
static void operator delete(void *ptr __attribute__((unused)),
size_t size __attribute__((unused)))
- { TRASH(ptr, size); }
+ { TRASH_FREE(ptr, size); }
Item *and_level;
Item_bool_func2 *cmp_func;
@@ -15788,9 +15814,10 @@ COND *
Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level_arg)
{
- if (args[0]->type() == Item::FIELD_ITEM)
+ Item *real_item= args[0]->real_item();
+ if (real_item->type() == Item::FIELD_ITEM)
{
- Field *field= ((Item_field*) args[0])->field;
+ Field *field= ((Item_field*) real_item)->field;
if (((field->type() == MYSQL_TYPE_DATE) ||
(field->type() == MYSQL_TYPE_DATETIME)) &&
@@ -17012,7 +17039,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
field->set_notnull();
memcpy(field->ptr,
orig_field->ptr_in_record(orig_field->table->s->default_values),
- field->pack_length());
+ field->pack_length_in_rec());
}
}
@@ -22236,7 +22263,10 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref)
SELECT list)
@param[in,out] all_fields All select, group and order by fields
@param[in] is_group_field True if order is a GROUP field, false if
- ORDER by field
+ ORDER by field
+ @param[in] add_to_all_fields If the item is to be added to all_fields and
+ ref_pointer_array, this flag can be set to
+ false to stop the automatic insertion.
@param[in] from_window_spec If true then order is from a window spec
@retval
@@ -22246,9 +22276,11 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref)
*/
static bool
-find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
+find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array,
+ TABLE_LIST *tables,
ORDER *order, List<Item> &fields, List<Item> &all_fields,
- bool is_group_field, bool from_window_spec)
+ bool is_group_field, bool add_to_all_fields,
+ bool from_window_spec)
{
Item *order_item= *order->item; /* The item from the GROUP/ORDER caluse. */
Item::Type order_item_type;
@@ -22385,6 +22417,9 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables
thd->is_error()))
return TRUE; /* Wrong field. */
+ if (!add_to_all_fields)
+ return FALSE;
+
uint el= all_fields.elements;
/* Add new field to field list. */
all_fields.push_front(order_item, thd->mem_root);
@@ -22413,7 +22448,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables
*/
int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
- List<Item> &fields, List<Item> &all_fields, ORDER *order,
+ List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool from_window_spec)
{
enum_parsing_place context_analysis_place=
@@ -22422,7 +22457,7 @@ int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
for (; order; order=order->next)
{
if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
- all_fields, FALSE, from_window_spec))
+ all_fields, false, true, from_window_spec))
return 1;
if ((*order->item)->with_window_func &&
context_analysis_place != IN_ORDER_BY)
@@ -22481,7 +22516,7 @@ setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
for (ord= order; ord; ord= ord->next)
{
if (find_order_in_list(thd, ref_pointer_array, tables, ord, fields,
- all_fields, TRUE, from_window_spec))
+ all_fields, true, true, from_window_spec))
return 1;
(*ord->item)->marker= UNDEF_POS; /* Mark found */
if ((*ord->item)->with_sum_func && context_analysis_place == IN_GROUP_BY)
@@ -22806,6 +22841,7 @@ get_sort_by_table(ORDER *a,ORDER *b, List<TABLE_LIST> &tables,
if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT)))
DBUG_RETURN(0);
+ map&= ~const_tables;
while ((table= ti++) && !(map & table->table->map)) ;
if (map != table->table->map)
DBUG_RETURN(0); // More than one table
@@ -24786,6 +24822,11 @@ int JOIN::save_explain_data_intern(Explain_query *output,
{
explain= new (output->mem_root) Explain_select(output->mem_root,
thd->lex->analyze_stmt);
+ if (!explain)
+ DBUG_RETURN(1); // EoM
+#ifndef DBUG_OFF
+ explain->select_lex= select_lex;
+#endif
join->select_lex->set_explain_type(true);
explain->select_id= join->select_lex->select_number;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 017f66a23b8..2003cc1211b 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1958,7 +1958,7 @@ int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab);
int get_quick_record(SQL_SELECT *select);
int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
- List<Item> &fields, List <Item> &all_fields, ORDER *order,
+ List<Item> &fields, List <Item> &all_fields, ORDER *order,
bool from_window_spec= false);
int setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order,
@@ -2036,7 +2036,7 @@ public:
@param thd - Current thread.
*/
static void *operator new(size_t size, THD *thd) throw();
- static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); }
+ static void operator delete(void *ptr, size_t size) {TRASH_FREE(ptr, size);}
Virtual_tmp_table(THD *thd)
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 60796df35d4..31be891553e 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2499,7 +2499,7 @@ public:
{ return alloc_root(mem_root, size); }
static void operator delete(void *ptr __attribute__((unused)),
size_t size __attribute__((unused)))
- { TRASH(ptr, size); }
+ { TRASH_FREE(ptr, size); }
my_thread_id thread_id;
uint32 os_thread_id;
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 1a4690a92f4..4f86d0dd0f1 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -185,7 +185,7 @@ public:
{
(void) ptr_arg;
(void) size;
- TRASH(ptr_arg, size);
+ TRASH_FREE(ptr_arg, size);
}
static void operator delete(void *, MEM_ROOT *)
{ /* never called */ }
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index d340f046691..da001674887 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1834,7 +1834,8 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
#endif
/* Write shadow frm file */
lpt->create_info->table_options= lpt->db_options;
- LEX_CUSTRING frm= build_frm_image(lpt->thd, lpt->table_name,
+ LEX_CUSTRING frm= build_frm_image(lpt->thd,
+ lpt->table_name,
lpt->create_info,
lpt->alter_info->create_list,
lpt->key_count, lpt->key_info_buffer,
@@ -6100,6 +6101,7 @@ remove_key:
#ifdef WITH_PARTITION_STORAGE_ENGINE
partition_info *tab_part_info= table->part_info;
+ thd->work_part_info= thd->lex->part_info;
if (tab_part_info)
{
/* ALTER TABLE ADD PARTITION IF NOT EXISTS */
@@ -6120,7 +6122,7 @@ remove_key:
ER_THD(thd, ER_SAME_NAME_PARTITION),
pe->partition_name);
alter_info->flags&= ~Alter_info::ALTER_ADD_PARTITION;
- thd->lex->part_info= NULL;
+ thd->work_part_info= NULL;
break;
}
}
@@ -9996,11 +9998,12 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
if ((int) key_nr >= 0)
{
const char *err_msg= ER_THD(thd, ER_DUP_ENTRY_WITH_KEY_NAME);
- if (key_nr == 0 &&
+ if (key_nr == 0 && to->s->keys > 0 &&
(to->key_info[0].key_part[0].field->flags &
AUTO_INCREMENT_FLAG))
err_msg= ER_THD(thd, ER_DUP_ENTRY_AUTOINCREMENT_CASE);
- print_keydup_error(to, key_nr == MAX_KEY ? NULL :
+ print_keydup_error(to,
+ key_nr >= to->s->keys ? NULL :
&to->key_info[key_nr],
err_msg, MYF(0));
}
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 0d0f8c4c309..303c5d75e18 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1357,11 +1357,12 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
List_iterator_fast<LEX_STRING> it_connection_cl_name(trigger_list->connection_cl_names);
List_iterator_fast<LEX_STRING> it_db_cl_name(trigger_list->db_cl_names);
List_iterator_fast<ulonglong> it_create_times(trigger_list->create_times);
- LEX *old_lex= thd->lex, lex;
+ LEX *old_lex= thd->lex, *old_stmt_lex= thd->stmt_lex;
+ LEX lex;
sp_rcontext *save_spcont= thd->spcont;
sql_mode_t save_sql_mode= thd->variables.sql_mode;
- thd->lex= &lex;
+ thd->lex= thd->stmt_lex= &lex;
save_db.str= thd->db;
save_db.length= thd->db_length;
@@ -1579,6 +1580,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
}
thd->reset_db(save_db.str, save_db.length);
thd->lex= old_lex;
+ thd->stmt_lex= old_stmt_lex;
thd->spcont= save_spcont;
thd->variables.sql_mode= save_sql_mode;
@@ -1592,6 +1594,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
err_with_lex_cleanup:
lex_end(&lex);
thd->lex= old_lex;
+ thd->stmt_lex= old_stmt_lex;
thd->spcont= save_spcont;
thd->variables.sql_mode= save_sql_mode;
thd->reset_db(save_db.str, save_db.length);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 6f63cc5d0eb..524f6eb9c8d 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -1362,22 +1362,6 @@ void st_select_lex_unit::reinit_exec_mechanism()
{
prepared= optimized= executed= 0;
optimize_started= 0;
-#ifndef DBUG_OFF
- if (is_union())
- {
- List_iterator_fast<Item> it(item_list);
- Item *field;
- while ((field= it++))
- {
- /*
- we can't cleanup here, because it broke link to temporary table field,
- but have to drop fixed flag to allow next fix_field of this field
- during re-executing
- */
- field->fixed= 0;
- }
- }
-#endif
if (with_element && with_element->is_recursive)
with_element->reset_recursive_for_exec();
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index c3bd16b974b..024fe53ce83 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1195,8 +1195,6 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
*/
mysql_derived_reinit(thd, NULL, table);
- thd->select_number+= table->view->number_of_selects;
-
DEBUG_SYNC(thd, "after_cached_view_opened");
DBUG_RETURN(0);
}
@@ -1351,7 +1349,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
lex_start(thd);
view_select= &lex->select_lex;
- view_select->select_number= ++thd->select_number;
+ view_select->select_number= ++thd->stmt_lex->current_select_number;
sql_mode_t saved_mode= thd->variables.sql_mode;
/* switch off modes which can prevent normal parsing of VIEW
@@ -1385,9 +1383,6 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
parse_status= parse_sql(thd, & parser_state, table->view_creation_ctx);
- lex->number_of_selects=
- (thd->select_number - view_select->select_number) + 1;
-
/* Restore environment. */
if ((old_lex->sql_command == SQLCOM_SHOW_FIELDS) ||
diff --git a/sql/table.cc b/sql/table.cc
index 3ff13fc9d87..b08ee380ec8 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1588,9 +1588,10 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
rec_buff_length= ALIGN_SIZE(share->reclength + 1);
share->rec_buff_length= rec_buff_length;
- if (!(record= (uchar *) alloc_root(&share->mem_root,
- rec_buff_length)))
+ if (!(record= (uchar *) alloc_root(&share->mem_root, rec_buff_length)))
goto err; /* purecov: inspected */
+ MEM_NOACCESS(record, rec_buff_length);
+ MEM_UNDEFINED(record, share->reclength);
share->default_values= record;
memcpy(record, frm_image + record_offset, share->reclength);
@@ -3059,6 +3060,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
if (!(record= (uchar*) alloc_root(&outparam->mem_root,
share->rec_buff_length * records)))
goto err; /* purecov: inspected */
+ MEM_NOACCESS(record, share->rec_buff_length * records);
if (records == 0)
{
@@ -3073,6 +3075,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
else
outparam->record[1]= outparam->record[0]; // Safety
}
+ MEM_UNDEFINED(outparam->record[0], share->reclength);
+ MEM_UNDEFINED(outparam->record[1], share->reclength);
if (!(field_ptr = (Field **) alloc_root(&outparam->mem_root,
(uint) ((share->fields+1)*
diff --git a/sql/transaction.cc b/sql/transaction.cc
index d01519b8bd4..0f1cd377198 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -611,12 +611,8 @@ bool trans_savepoint(THD *thd, LEX_STRING name)
!opt_using_transactions)
DBUG_RETURN(FALSE);
- enum xa_states xa_state= thd->transaction.xid_state.xa_state;
- if (xa_state != XA_NOTR && xa_state != XA_ACTIVE)
- {
- my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ if (thd->transaction.xid_state.check_has_uncommitted_xa())
DBUG_RETURN(TRUE);
- }
sv= find_savepoint(thd, name);
@@ -691,12 +687,8 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name)
DBUG_RETURN(TRUE);
}
- enum xa_states xa_state= thd->transaction.xid_state.xa_state;
- if (xa_state != XA_NOTR)
- {
- my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ if (thd->transaction.xid_state.check_has_uncommitted_xa())
DBUG_RETURN(TRUE);
- }
/**
Checking whether it is safe to release metadata locks acquired after
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 899b612bd89..ff2b406350a 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
- Copyright (c) 2009, 2013, Monty Program Ab.
+ Copyright (c) 2009, 2018, MariaDB Corporation
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
@@ -87,7 +87,7 @@ static uchar *extra2_write(uchar *pos, enum extra2_frm_value_type type,
return extra2_write(pos, type, reinterpret_cast<LEX_STRING *>(str));
}
-/**
+/*
Create a frm (table definition) file
@param thd Thread handler
@@ -175,7 +175,8 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
DBUG_PRINT("info", ("Options length: %u", options_len));
if (validate_comment_length(thd, &create_info->comment, TABLE_COMMENT_MAXLEN,
- ER_TOO_LONG_TABLE_COMMENT, table))
+ ER_TOO_LONG_TABLE_COMMENT,
+ table))
DBUG_RETURN(frm);
/*
If table comment is longer than TABLE_COMMENT_INLINE_MAXLEN bytes,
@@ -280,6 +281,14 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
DBUG_ASSERT(pos == frm_ptr + uint2korr(fileinfo+6));
key_info_length= pack_keys(pos, keys, key_info, data_offset);
+ if (key_info_length > UINT_MAX16)
+ {
+ my_printf_error(ER_CANT_CREATE_TABLE,
+ "Cannot create table %`s: index information is too long. "
+ "Decrease number of indexes or use shorter index names or shorter comments.",
+ MYF(0), table);
+ goto err;
+ }
int2store(forminfo+2, frm.length - filepos);
int4store(fileinfo+10, frm.length);
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index 8626cb07196..ba611fed0c7 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -30,9 +30,10 @@
#include <cstdio>
#include <cstdlib>
-char wsrep_defaults_file[FN_REFLEN * 2 + 10 +
- sizeof(WSREP_SST_OPT_CONF) +
- sizeof(WSREP_SST_OPT_EXTRA_CONF)] = {0};
+static char wsrep_defaults_file[FN_REFLEN * 2 + 10 + 30 +
+ sizeof(WSREP_SST_OPT_CONF) +
+ sizeof(WSREP_SST_OPT_CONF_SUFFIX) +
+ sizeof(WSREP_SST_OPT_CONF_EXTRA)] = {0};
// container for real auth string
static const char* sst_auth_real = NULL;
@@ -69,7 +70,11 @@ static void make_wsrep_defaults_file()
if (my_defaults_extra_file)
ptr= strxnmov(ptr, end - ptr,
- WSREP_SST_OPT_EXTRA_CONF, " '", my_defaults_extra_file, "' ", NULL);
+ WSREP_SST_OPT_CONF_EXTRA, " '", my_defaults_extra_file, "' ", NULL);
+
+ if (my_defaults_group_suffix)
+ ptr= strxnmov(ptr, end - ptr,
+ WSREP_SST_OPT_CONF_SUFFIX, " '", my_defaults_group_suffix, "' ", NULL);
}
}
@@ -630,8 +635,8 @@ static ssize_t sst_prepare_other (const char* method,
WSREP_SST_OPT_PARENT" '%d'"
" %s '%s' ",
method, addr_in, mysql_real_data_home,
- wsrep_defaults_file, (int)getpid(),
- binlog_opt, binlog_opt_val);
+ wsrep_defaults_file,
+ (int)getpid(), binlog_opt, binlog_opt_val);
my_free(binlog_opt_val);
if (ret < 0 || ret >= cmd_len)
@@ -913,7 +918,7 @@ static int sst_donate_mysqldump (const char* addr,
WSREP_SST_OPT_PORT" '%d' "
WSREP_SST_OPT_LPORT" '%u' "
WSREP_SST_OPT_SOCKET" '%s' "
- " %s "
+ " '%s' "
WSREP_SST_OPT_GTID" '%s:%lld' "
WSREP_SST_OPT_GTID_DOMAIN_ID" '%d'"
"%s",
diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h
index 460046bc4ad..8bf6dc31464 100644
--- a/sql/wsrep_sst.h
+++ b/sql/wsrep_sst.h
@@ -27,7 +27,8 @@
#define WSREP_SST_OPT_AUTH "--auth"
#define WSREP_SST_OPT_DATA "--datadir"
#define WSREP_SST_OPT_CONF "--defaults-file"
-#define WSREP_SST_OPT_EXTRA_CONF "--defaults-extra-file"
+#define WSREP_SST_OPT_CONF_SUFFIX "--defaults-group-suffix"
+#define WSREP_SST_OPT_CONF_EXTRA "--defaults-extra-file"
#define WSREP_SST_OPT_PARENT "--parent"
#define WSREP_SST_OPT_BINLOG "--binlog"