diff options
author | Sergei Golubchik <serg@mariadb.org> | 2018-02-06 14:50:50 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2018-02-06 14:50:50 +0100 |
commit | 4771ae4b22d2bdef0aafc563570c71d4636a2493 (patch) | |
tree | d115bd7c68b1e6feab68ff6fcd547e0c86c79296 /sql | |
parent | 60f51af755ea9d07c20a596ba21de184816fa265 (diff) | |
parent | 0c25e58db6b045df92c209d396031cac5b528bbf (diff) | |
download | mariadb-git-4771ae4b22d2bdef0aafc563570c71d4636a2493.tar.gz |
Merge branch 'github/10.1' into 10.2
Diffstat (limited to 'sql')
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> ¶meters) { + 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, ©); 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" |