diff options
author | Jan Lindström <jan.lindstrom@mariadb.com> | 2018-02-01 14:09:48 +0200 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2018-02-01 14:09:48 +0200 |
commit | c7e5feb2596e2a032207191320dbf1387d440959 (patch) | |
tree | b4a5f850c3ab553a9a3c6b1b58bc5280ed42a861 /sql | |
parent | 08b2c516da4df91082ae9fbe5e060959c4bb5faa (diff) | |
parent | d01dbe66a8bf9cb6031f95159c49100f9299a768 (diff) | |
download | mariadb-git-c7e5feb2596e2a032207191320dbf1387d440959.tar.gz |
Merge tag 'mariadb-10.0.34' into 10.0-galeramariadb-galera-10.0.34
Conflicts:
storage/innobase/lock/lock0lock.cc
storage/xtradb/lock/lock0lock.cc
storage/xtradb/lock/lock0wait.cc
support-files/mysql.server.sh
Diffstat (limited to 'sql')
60 files changed, 621 insertions, 275 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index a3904dd356f..2bb68c7ec46 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, 2015, MariaDB +# Copyright (c) 2010, 2018, MariaDB # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by 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 7074cc2cbc4..c36fff06a07 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1873,7 +1873,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) { @@ -4390,7 +4390,7 @@ double Field_double::val_real(void) return j; } -longlong Field_double::val_int(void) +longlong Field_double::val_int_from_real(bool want_unsigned_result) { ASSERT_COLUMN_MARKED_FOR_READ; double j; @@ -4398,8 +4398,15 @@ longlong Field_double::val_int(void) bool error; float8get(j,ptr); - res= double_to_longlong(j, 0, &error); - if (error) + res= double_to_longlong(j, want_unsigned_result, &error); + /* + Note, val_uint() is currently used for auto_increment purposes only, + and we want to suppress all warnings in such cases. + If we ever start using val_uint() for other purposes, + val_int_from_real() will need a new separate parameter to + suppress warnings. + */ + if (error && !want_unsigned_result) { ErrConvDouble err(j); push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, @@ -8704,7 +8711,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 e7bd5532ae6..5286dd49dde 100644 --- a/sql/field.h +++ b/sql/field.h @@ -301,7 +301,7 @@ public: { return alloc_root(mem_root, size); } static void *operator new(size_t size) throw () { return sql_alloc(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); } @@ -420,6 +420,10 @@ public: enum_check_fields check_level); virtual double val_real(void)=0; virtual longlong val_int(void)=0; + virtual ulonglong val_uint(void) + { + return (ulonglong) val_int(); + } virtual my_decimal *val_decimal(my_decimal *); inline String *val_str(String *str) { return val_str(str, str); } /* @@ -1554,6 +1558,7 @@ private: class Field_double :public Field_real { + longlong val_int_from_real(bool want_unsigned_result); public: Field_double(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, @@ -1580,7 +1585,8 @@ public: int store(longlong nr, bool unsigned_val); int reset(void) { bzero(ptr,sizeof(double)); return 0; } double val_real(void); - longlong val_int(void); + longlong val_int(void) { return val_int_from_real(false); } + ulonglong val_uint(void) { return (ulonglong) val_int_from_real(true); } String *val_str(String*,String *); bool send_binary(Protocol *protocol); int cmp(const uchar *,const uchar *); diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 5006266eaed..ec3e6c3aaaf 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -590,7 +590,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; @@ -641,9 +641,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/filesort.cc b/sql/filesort.cc index 8a7d5610dc2..873597480a2 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -987,7 +987,8 @@ static void make_sortkey(register Sort_param *param, if (maybe_null) *to++=1; char *tmp_buffer= param->tmp_buffer ? param->tmp_buffer : (char*)to; - String tmp(tmp_buffer, param->sort_length, cs); + String tmp(tmp_buffer, param->tmp_buffer ? param->sort_length : + sort_field->length, cs); String *res= item->str_result(&tmp); if (!res) { diff --git a/sql/filesort_utils.cc b/sql/filesort_utils.cc index 1cef30b6a56..bc0fe4712b6 100644 --- a/sql/filesort_utils.cc +++ b/sql/filesort_utils.cc @@ -96,7 +96,7 @@ uchar **Filesort_buffer::alloc_sort_buffer(uint num_records, uint record_length) if (m_idx_array.is_null()) { - sort_buff_sz= num_records * (record_length + sizeof(uchar*)); + sort_buff_sz= ((size_t)num_records) * (record_length + sizeof(uchar*)); set_if_bigger(sort_buff_sz, record_length * MERGEBUFF2); uchar **sort_keys= (uchar**) my_malloc(sort_buff_sz, MYF(MY_THREAD_SPECIFIC)); diff --git a/sql/handler.cc b/sql/handler.cc index f6ae797fb52..657cb01cbc8 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3413,9 +3413,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 { @@ -3507,11 +3509,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/handler.h b/sql/handler.h index 51b301ae22e..2c46368869c 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1676,6 +1676,13 @@ struct HA_CREATE_INFO used_fields|= (HA_CREATE_USED_CHARSET | HA_CREATE_USED_DEFAULT_CHARSET); return false; } + ulong table_options_with_row_type() + { + if (row_type == ROW_TYPE_DYNAMIC || row_type == ROW_TYPE_PAGE) + return table_options | HA_OPTION_PACK_RECORD; + else + return table_options; + } }; diff --git a/sql/item.cc b/sql/item.cc index 050b37f6124..5f8cf6c80f7 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 @@ -2745,7 +2745,8 @@ table_map Item_field::all_used_tables() const return (get_depended_from() ? OUTER_REF_TABLE_BIT : field->table->map); } -void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) { if (new_parent == get_depended_from()) depended_from= NULL; @@ -2789,6 +2790,19 @@ void Item_field::fix_after_pullout(st_select_lex *new_parent, Item **ref) if (!need_change) return; + if (!merge) + { + /* + It is transformation without merge. + This field was "outer" for the inner SELECT where it was taken and + moved up. + "Outer" fields uses normal SELECT_LEX context of upper SELECTs for + name resolution, so we can switch everything to it safely. + */ + this->context= &new_parent->context; + return; + } + Name_resolution_context *ctx= new Name_resolution_context(); if (context->select_lex == new_parent) { @@ -4719,7 +4733,8 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && select->having_fix_field && - select_ref != not_found_item && !group_by_ref) + select_ref != not_found_item && !group_by_ref && + !ref->alias_name_used) { /* Report the error if fields was found only in the SELECT item list and @@ -8107,18 +8122,20 @@ bool Item_outer_ref::fix_fields(THD *thd, Item **reference) } -void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_outer_ref::fix_after_pullout(st_select_lex *new_parent, + Item **ref, bool merge) { if (get_depended_from() == new_parent) { *ref= outer_ref; - (*ref)->fix_after_pullout(new_parent, ref); + (*ref)->fix_after_pullout(new_parent, ref, merge); } } -void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr) +void Item_ref::fix_after_pullout(st_select_lex *new_parent, Item **refptr, + bool merge) { - (*ref)->fix_after_pullout(new_parent, ref); + (*ref)->fix_after_pullout(new_parent, ref, merge); if (get_depended_from() == new_parent) depended_from= NULL; } @@ -8463,7 +8480,7 @@ Item *Item_default_value::transform(Item_transformer transformer, uchar *args) 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); } @@ -9987,7 +10004,7 @@ const char *dbug_print_item(Item *item) if (!item) return "(Item*)NULL"; item->print(&str ,QT_ORDINARY); - 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 d6b505b67b8..7856328a33b 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 @@ -49,6 +49,12 @@ bool trace_unsupported_by_check_vcol_func_processor(const char *where) return trace_unsupported_func(where, "check_vcol_func_processor"); } +#ifdef DBUG_OFF +static inline const char *dbug_print_item(Item *item) { return NULL; } +#else +extern const char *dbug_print_item(Item *item); +#endif + class Protocol; struct TABLE_LIST; void item_init(void); /* Init item functions */ @@ -595,7 +601,7 @@ public: { return sql_alloc(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) {} enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM, @@ -706,7 +712,9 @@ public: Fix after some tables has been pulled out. Basically re-calculate all attributes that are dependent on the tables. */ - virtual void fix_after_pullout(st_select_lex *new_parent, Item **ref) {}; + virtual void fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) + {}; /* This method should be used in case where we are sure that we do not need @@ -2256,7 +2264,7 @@ public: bool send(Protocol *protocol, String *str_arg); void reset_field(Field *f); bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void make_field(Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); void save_org_in_field(Field *field, fast_field_copier optimizer_data); @@ -3410,7 +3418,7 @@ public: bool send(Protocol *prot, String *tmp); void make_field(Send_field *field); bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); int save_in_field(Field *field, bool no_conversions); void save_org_in_field(Field *field, fast_field_copier optimizer_data); fast_field_copier setup_fast_field_copier(Field *field) @@ -3664,9 +3672,9 @@ public: Item *it= ((Item *) item)->real_item(); return orig_item->eq(it, binary_cmp); } - void fix_after_pullout(st_select_lex *new_parent, Item **refptr) + void fix_after_pullout(st_select_lex *new_parent, Item **refptr, bool merge) { - orig_item->fix_after_pullout(new_parent, &orig_item); + orig_item->fix_after_pullout(new_parent, &orig_item, merge); } int save_in_field(Field *to, bool no_conversions); enum Item_result result_type () const { return orig_item->result_type(); } @@ -3924,7 +3932,7 @@ public: outer_ref->save_org_in_field(result_field, NULL); } bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); table_map used_tables() const { return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 0134f628c80..d1c62859d20 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1442,10 +1442,12 @@ bool Item_in_optimizer::is_top_level_item() } -void Item_in_optimizer::fix_after_pullout(st_select_lex *new_parent, Item **ref) +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); + Item_bool_func::fix_after_pullout(new_parent, ref, merge); /* Then, re-calculate not_null_tables_cache: */ eval_not_null_tables(NULL); @@ -1467,6 +1469,33 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *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"); @@ -1644,6 +1673,7 @@ Item *Item_in_optimizer::expr_cache_insert_transformer(uchar *thd_arg) { THD *thd= (THD*) thd_arg; DBUG_ENTER("Item_in_optimizer::expr_cache_insert_transformer"); + DBUG_ASSERT(fixed); if (invisible_mode()) DBUG_RETURN(this); @@ -1668,6 +1698,7 @@ Item *Item_in_optimizer::expr_cache_insert_transformer(uchar *thd_arg) 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()) { @@ -1905,6 +1936,7 @@ Item *Item_in_optimizer::transform(Item_transformer transformer, { Item *new_item; + DBUG_ASSERT(fixed); DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare()); DBUG_ASSERT(arg_count == 2); @@ -1956,6 +1988,7 @@ Item *Item_in_optimizer::transform(Item_transformer transformer, bool Item_in_optimizer::is_expensive_processor(uchar *arg) { + DBUG_ASSERT(fixed); return args[0]->is_expensive_processor(arg) || args[1]->is_expensive_processor(arg); } @@ -1963,6 +1996,7 @@ bool Item_in_optimizer::is_expensive_processor(uchar *arg) bool Item_in_optimizer::is_expensive() { + DBUG_ASSERT(fixed); return args[0]->is_expensive() || args[1]->is_expensive(); } @@ -2064,6 +2098,19 @@ bool Item_func_opt_neg::eq(const Item *item, bool binary_cmp) const } +bool Item_func_interval::fix_fields(THD *thd, Item **ref) +{ + if (Item_int_func::fix_fields(thd, ref)) + return true; + for (uint i= 0 ; i < row->cols(); i++) + { + if (row->element_index(i)->check_cols(1)) + return true; + } + return false; +} + + void Item_func_interval::fix_length_and_dec() { uint rows= row->cols(); @@ -2288,10 +2335,11 @@ bool Item_func_between::count_sargable_conds(uchar *arg) } -void Item_func_between::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_func_between::fix_after_pullout(st_select_lex *new_parent, + Item **ref, bool merge) { /* This will re-calculate attributes of the arguments */ - Item_func_opt_neg::fix_after_pullout(new_parent, ref); + Item_func_opt_neg::fix_after_pullout(new_parent, ref, merge); /* Then, re-calculate not_null_tables_cache according to our special rules */ eval_not_null_tables(NULL); } @@ -2681,10 +2729,11 @@ Item_func_if::eval_not_null_tables(uchar *opt_arg) } -void Item_func_if::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_func_if::fix_after_pullout(st_select_lex *new_parent, + Item **ref, bool merge) { /* This will re-calculate attributes of the arguments */ - Item_func::fix_after_pullout(new_parent, ref); + Item_func::fix_after_pullout(new_parent, ref, merge); /* Then, re-calculate not_null_tables_cache according to our special rules */ eval_not_null_tables(NULL); } @@ -4010,10 +4059,11 @@ Item_func_in::eval_not_null_tables(uchar *opt_arg) } -void Item_func_in::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_func_in::fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) { /* This will re-calculate attributes of the arguments */ - Item_func_opt_neg::fix_after_pullout(new_parent, ref); + Item_func_opt_neg::fix_after_pullout(new_parent, ref, merge); /* Then, re-calculate not_null_tables_cache according to our special rules */ eval_not_null_tables(NULL); } @@ -4497,7 +4547,8 @@ Item_cond::eval_not_null_tables(uchar *opt_arg) } -void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) { List_iterator<Item> li(list); Item *item; @@ -4511,7 +4562,7 @@ void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref) while ((item=li++)) { table_map tmp_table_map; - item->fix_after_pullout(new_parent, li.ref()); + item->fix_after_pullout(new_parent, li.ref(), merge); item= *li.ref(); used_tables_cache|= item->used_tables(); const_item_cache&= item->const_item(); @@ -5203,7 +5254,7 @@ void Regexp_processor_pcre::pcre_exec_warn(int rc) const switch (rc) { case PCRE_ERROR_NULL: - errmsg= "pcre_exec: null arguement passed"; + errmsg= "pcre_exec: null argument passed"; break; case PCRE_ERROR_BADOPTION: errmsg= "pcre_exec: bad option"; @@ -6637,7 +6688,7 @@ longlong Item_func_dyncol_exists::val_int() null_value= 1; return 1; } - if (my_charset_same(nm->charset(), &my_charset_utf8_general_ci)) + if (my_charset_same(nm->charset(), DYNCOL_UTF)) { buf.str= (char *) nm->ptr(); buf.length= nm->length(); @@ -6647,11 +6698,11 @@ longlong Item_func_dyncol_exists::val_int() uint strlen; uint dummy_errors; buf.str= (char *)sql_alloc((strlen= nm->length() * - my_charset_utf8_general_ci.mbmaxlen + 1)); + DYNCOL_UTF->mbmaxlen + 1)); if (buf.str) { buf.length= - copy_and_convert(buf.str, strlen, &my_charset_utf8_general_ci, + copy_and_convert(buf.str, strlen, DYNCOL_UTF, nm->ptr(), nm->length(), nm->charset(), &dummy_errors); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index ba0af32d76f..6d81c7acc40 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -272,9 +272,11 @@ public: virtual void get_cache_parameters(List<Item> ¶meters); bool is_top_level_item(); bool eval_not_null_tables(uchar *opt_arg); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + 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(); }; class Comp_creator @@ -689,7 +691,7 @@ public: virtual void print(String *str, enum_query_type query_type); CHARSET_INFO *compare_collation() { return cmp_collation.collation; } bool eval_not_null_tables(uchar *opt_arg); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); bool count_sargable_conds(uchar *arg); }; @@ -729,6 +731,7 @@ public: { allowed_arg_cols= 0; // Fetch this value from first argument } + bool fix_fields(THD *, Item **); longlong val_int(); void fix_length_and_dec(); const char *func_name() const { return "interval"; } @@ -791,7 +794,7 @@ public: uint decimal_precision() const; const char *func_name() const { return "if"; } bool eval_not_null_tables(uchar *opt_arg); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); private: void cache_type_info(Item *source); }; @@ -1337,7 +1340,7 @@ public: bool nulls_in_row(); CHARSET_INFO *compare_collation() { return cmp_collation.collation; } bool eval_not_null_tables(uchar *opt_arg); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); }; class cmp_item_row :public cmp_item @@ -1387,9 +1390,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)) && @@ -1729,7 +1732,7 @@ public: list.concat(nlist); } bool fix_fields(THD *, Item **ref); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); enum Type type() const { return COND_ITEM; } List<Item>* argument_list() { return &list; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 7e4ddb7427c..cf49612feb4 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -265,7 +265,8 @@ Item_func::eval_not_null_tables(uchar *opt_arg) } -void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) { Item **arg,**arg_end; @@ -276,7 +277,7 @@ void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref) { for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) { - (*arg)->fix_after_pullout(new_parent, arg); + (*arg)->fix_after_pullout(new_parent, arg, merge); Item *item= *arg; used_tables_cache|= item->used_tables(); @@ -593,6 +594,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; @@ -609,6 +611,7 @@ void Item_udf_func::fix_num_length_and_dec() max_length= float_length(NOT_FIXED_DEC); } } +#endif /** diff --git a/sql/item_func.h b/sql/item_func.h index 5db92b6f3fe..7dea193c99b 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -143,7 +143,7 @@ public: // Constructor used for Item_cond_and/or (see Item comment) Item_func(THD *thd, Item_func *item); bool fix_fields(THD *, Item **ref); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void quick_fix_field(); table_map used_tables() const; table_map not_null_tables() const; diff --git a/sql/item_inetfunc.cc b/sql/item_inetfunc.cc index 6a09747fa1a..4c4dfa4497b 100644 --- a/sql/item_inetfunc.cc +++ b/sql/item_inetfunc.cc @@ -181,7 +181,8 @@ String *Item_func_inet_str_base::val_str_ascii(String *buffer) return NULL; } - String *arg_str= args[0]->val_str(buffer); + StringBuffer<STRING_BUFFER_USUAL_SIZE> tmp; + String *arg_str= args[0]->val_str(&tmp); if (!arg_str) // Out-of memory happened. The error has been reported. { // Or: the underlying field is NULL null_value= true; @@ -679,7 +680,7 @@ static void ipv6_to_str(const in6_addr *ipv6, char *str) @retval true The string has been converted sucessfully. */ -bool Item_func_inet6_aton::calc_value(String *arg, String *buffer) +bool Item_func_inet6_aton::calc_value(const String *arg, String *buffer) { // ipv4-string -> varbinary(4) // ipv6-string -> varbinary(16) @@ -719,7 +720,7 @@ bool Item_func_inet6_aton::calc_value(String *arg, String *buffer) @retval true The string has been converted sucessfully. */ -bool Item_func_inet6_ntoa::calc_value(String *arg, String *buffer) +bool Item_func_inet6_ntoa::calc_value(const String *arg, String *buffer) { if (arg->charset() != &my_charset_bin) return false; diff --git a/sql/item_inetfunc.h b/sql/item_inetfunc.h index 3a85d367ff1..d6fcc07a1c6 100644 --- a/sql/item_inetfunc.h +++ b/sql/item_inetfunc.h @@ -99,7 +99,7 @@ public: virtual String *val_str_ascii(String *buffer); protected: - virtual bool calc_value(String *arg, String *buffer) = 0; + virtual bool calc_value(const String *arg, String *buffer) = 0; }; @@ -126,7 +126,7 @@ public: } protected: - virtual bool calc_value(String *arg, String *buffer); + virtual bool calc_value(const String *arg, String *buffer); }; @@ -158,7 +158,7 @@ public: } protected: - virtual bool calc_value(String *arg, String *buffer); + virtual bool calc_value(const String *arg, String *buffer); }; diff --git a/sql/item_row.cc b/sql/item_row.cc index b38cffd1ad5..c07ea612850 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -184,14 +184,15 @@ void Item_row::update_used_tables() } -void Item_row::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_row::fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) { used_tables_cache= 0; const_item_cache= 1; not_null_tables_cache= 0; for (uint i= 0; i < arg_count; i++) { - items[i]->fix_after_pullout(new_parent, &items[i]); + items[i]->fix_after_pullout(new_parent, &items[i], merge); used_tables_cache|= items[i]->used_tables(); const_item_cache&= items[i]->const_item(); not_null_tables_cache|= items[i]->not_null_tables(); diff --git a/sql/item_row.h b/sql/item_row.h index 4d5c20711b5..ae9599baa57 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -65,7 +65,7 @@ public: return 0; }; bool fix_fields(THD *thd, Item **ref); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void cleanup(); void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); table_map used_tables() const { return used_tables_cache; }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c3043adac47..c0d60d7ef8b 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 @@ -252,9 +252,9 @@ String *Item_func_sha2::val_str_ascii(String *str) size_t input_len; uint digest_length= 0; + 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; @@ -2905,6 +2905,20 @@ String *Item_func_make_set::val_str(String *str) } +void Item_func_char::print(String *str, enum_query_type query_type) +{ + str->append(Item_func_char::func_name()); + str->append('('); + print_args(str, 0, query_type); + if (collation.collation != &my_charset_bin) + { + str->append(C_STRING_WITH_LEN(" using ")); + str->append(collation.collation->csname); + } + str->append(')'); +} + + String *Item_func_char::val_str(String *str) { DBUG_ASSERT(fixed == 1); @@ -4444,7 +4458,7 @@ bool Item_func_dyncol_create::prepare_arguments(bool force_names_arg) if (res) { // guaranty UTF-8 string for names - if (my_charset_same(res->charset(), &my_charset_utf8_general_ci)) + if (my_charset_same(res->charset(), DYNCOL_UTF)) { keys_str[i].length= res->length(); keys_str[i].str= sql_strmake(res->ptr(), res->length()); @@ -4455,11 +4469,11 @@ bool Item_func_dyncol_create::prepare_arguments(bool force_names_arg) uint dummy_errors; char *str= (char *)sql_alloc((strlen= res->length() * - my_charset_utf8_general_ci.mbmaxlen + 1)); + DYNCOL_UTF->mbmaxlen + 1)); if (str) { keys_str[i].length= - copy_and_convert(str, strlen, &my_charset_utf8_general_ci, + copy_and_convert(str, strlen, DYNCOL_UTF, res->ptr(), res->length(), res->charset(), &dummy_errors); keys_str[i].str= str; @@ -4680,9 +4694,10 @@ String *Item_func_dyncol_json::val_str(String *str) size_t length, alloc_length; dynstr_reassociate(&json, &ptr, &length, &alloc_length); str->reassociate(ptr, (uint32) length, (uint32) alloc_length, - &my_charset_utf8_general_ci); + DYNCOL_UTF); null_value= FALSE; } + str->set_charset(DYNCOL_UTF); return str; null: @@ -4781,7 +4796,7 @@ bool Item_dyncol_get::get_dyn_value(DYNAMIC_COLUMN_VALUE *val, String *tmp) return 1; } - if (my_charset_same(nm->charset(), &my_charset_utf8_general_ci)) + if (my_charset_same(nm->charset(), DYNCOL_UTF)) { buf.str= (char *) nm->ptr(); buf.length= nm->length(); @@ -4791,11 +4806,11 @@ bool Item_dyncol_get::get_dyn_value(DYNAMIC_COLUMN_VALUE *val, String *tmp) uint strlen; uint dummy_errors; buf.str= (char *)sql_alloc((strlen= nm->length() * - my_charset_utf8_general_ci.mbmaxlen + 1)); + DYNCOL_UTF->mbmaxlen + 1)); if (buf.str) { buf.length= - copy_and_convert(buf.str, strlen, &my_charset_utf8_general_ci, + copy_and_convert(buf.str, strlen, DYNCOL_UTF, nm->ptr(), nm->length(), nm->charset(), &dummy_errors); } @@ -5229,7 +5244,6 @@ String *Item_func_dyncol_list::val_str(String *str) goto null; str->length(0); - str->set_charset(&my_charset_utf8_general_ci); for (i= 0; i < count; i++) { append_identifier(current_thd, str, names[i].str, names[i].length); @@ -5239,6 +5253,7 @@ String *Item_func_dyncol_list::val_str(String *str) null_value= FALSE; if (names) my_free(names); + str->set_charset(DYNCOL_UTF); return str; null: diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 1b133d1d885..aa3486d4e73 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -702,6 +702,7 @@ public: max_length= arg_count * 4; } const char *func_name() const { return "char"; } + void print(String *str, enum_query_type query_type); }; @@ -1177,14 +1178,14 @@ public: class Item_func_dyncol_json: public Item_str_func { public: - Item_func_dyncol_json(Item *str) :Item_str_func(str) {} + Item_func_dyncol_json(Item *str) :Item_str_func(str) + {collation.set(DYNCOL_UTF);} const char *func_name() const{ return "column_json"; } String *val_str(String *); void fix_length_and_dec() { max_length= MAX_BLOB_WIDTH; maybe_null= 1; - collation.set(&my_charset_bin); decimals= 0; } }; @@ -1218,7 +1219,8 @@ public: class Item_func_dyncol_list: public Item_str_func { public: - Item_func_dyncol_list(Item *str) :Item_str_func(str) {}; + Item_func_dyncol_list(Item *str) :Item_str_func(str) + {collation.set(DYNCOL_UTF);}; void fix_length_and_dec() { maybe_null= 1; max_length= MAX_BLOB_WIDTH; }; const char *func_name() const{ return "column_list"; } String *val_str(String *); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index a215092f30f..8e8748be87a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -446,7 +446,8 @@ bool Item_subselect::mark_as_dependent(THD *thd, st_select_lex *select, OUTER_REF_TABLE_BIT. */ -void Item_subselect::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_subselect::fix_after_pullout(st_select_lex *new_parent, + Item **ref, bool merge) { recalc_used_tables(new_parent, TRUE); parent_select= new_parent; @@ -1110,7 +1111,8 @@ Item_singlerow_subselect::select_transformer(JOIN *join) /* as far as we moved content to upper level we have to fix dependences & Co */ - substitution->fix_after_pullout(select_lex->outer_select(), &substitution); + substitution->fix_after_pullout(select_lex->outer_select(), + &substitution, TRUE); } DBUG_RETURN(false); } @@ -2855,7 +2857,7 @@ bool Item_exists_subselect::exists2in_processor(uchar *opt_arg) goto out; } } - outer_exp->fix_after_pullout(unit->outer_select(), &outer_exp); + outer_exp->fix_after_pullout(unit->outer_select(), &outer_exp, FALSE); outer_exp->update_used_tables(); outer.push_back(outer_exp); } @@ -3228,10 +3230,11 @@ err: } -void Item_in_subselect::fix_after_pullout(st_select_lex *new_parent, Item **ref) +void Item_in_subselect::fix_after_pullout(st_select_lex *new_parent, + Item **ref, bool merge) { - left_expr->fix_after_pullout(new_parent, &left_expr); - Item_subselect::fix_after_pullout(new_parent, ref); + left_expr->fix_after_pullout(new_parent, &left_expr, merge); + Item_subselect::fix_after_pullout(new_parent, ref, merge); used_tables_cache |= left_expr->used_tables(); } @@ -5385,7 +5388,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_subselect.h b/sql/item_subselect.h index ad43215e437..769be7ee925 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -172,7 +172,7 @@ public: } bool fix_fields(THD *thd, Item **ref); bool mark_as_dependent(THD *thd, st_select_lex *select, Item *item); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void recalc_used_tables(st_select_lex *new_parent, bool after_pullout); virtual bool exec(); /* @@ -608,7 +608,7 @@ public: virtual void print(String *str, enum_query_type query_type); bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); bool const_item() const { return Item_subselect::const_item() && left_expr->const_item(); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 0f10d832ba6..7b017cd810a 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3670,7 +3670,7 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type) } } str->append(STRING_WITH_LEN(" separator \'")); - str->append(*separator); + str->append_for_single_quote(separator->ptr(), separator->length()); str->append(STRING_WITH_LEN("\')")); } diff --git a/sql/key.cc b/sql/key.cc index aaaea9391c6..414c3392cff 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -65,7 +65,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 */ @@ -84,7 +85,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 5ab46ee9368..c57331df807 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4085,8 +4085,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 45e6b3666bf..8575709203c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4081,7 +4081,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"); return 1; } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7b29e8b2b7b..f1d84e5c623 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2671,7 +2671,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/opt_subselect.cc b/sql/opt_subselect.cc index 6bf122fac5a..67205a52cac 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1794,7 +1794,8 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) Walk through sj nest's WHERE and ON expressions and call item->fix_table_changes() for all items. */ - sj_nest->sj_on_expr->fix_after_pullout(parent_lex, &sj_nest->sj_on_expr); + sj_nest->sj_on_expr->fix_after_pullout(parent_lex, &sj_nest->sj_on_expr, + TRUE); fix_list_after_tbl_changes(parent_lex, &sj_nest->nested_join->join_list); @@ -1953,7 +1954,7 @@ static bool convert_subq_to_jtbm(JOIN *parent_join, DBUG_ASSERT(parent_join->table_count < MAX_TABLES); Item *conds= hash_sj_engine->semi_join_conds; - conds->fix_after_pullout(parent_lex, &conds); + conds->fix_after_pullout(parent_lex, &conds, TRUE); DBUG_EXECUTE("where", print_where(conds,"SJ-EXPR", QT_ORDINARY);); @@ -2005,7 +2006,7 @@ void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist) while ((table= it++)) { if (table->on_expr) - table->on_expr->fix_after_pullout(new_parent, &table->on_expr); + table->on_expr->fix_after_pullout(new_parent, &table->on_expr, TRUE); if (table->nested_join) fix_list_after_tbl_changes(new_parent, &table->nested_join->join_list); } @@ -2691,7 +2692,8 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, LooseScan detector in best_access_path) */ remaining_tables &= ~new_join_tab->table->map; - table_map dups_producing_tables; + table_map dups_producing_tables, prev_dups_producing_tables, + prev_sjm_lookup_tables; if (idx == join->const_tables) dups_producing_tables= 0; @@ -2702,7 +2704,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, if ((emb_sj_nest= new_join_tab->emb_sj_nest)) dups_producing_tables |= emb_sj_nest->sj_inner_tables; - Semi_join_strategy_picker **strategy; + Semi_join_strategy_picker **strategy, **prev_strategy; if (idx == join->const_tables) { /* First table, initialize pickers */ @@ -2754,23 +2756,54 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, 3. We have no clue what to do about fanount of semi-join Y. */ if ((dups_producing_tables & handled_fanout) || - (read_time < *current_read_time && + (read_time < *current_read_time && !(handled_fanout & pos->inner_tables_handled_with_other_sjs))) { - /* Mark strategy as used */ - (*strategy)->mark_used(); - pos->sj_strategy= sj_strategy; - if (sj_strategy == SJ_OPT_MATERIALIZE) - join->sjm_lookup_tables |= handled_fanout; + DBUG_ASSERT(pos->sj_strategy != sj_strategy); + /* + If the strategy choosen first time or + the strategy replace strategy which was used to exectly the same + tables + */ + if (pos->sj_strategy == SJ_OPT_NONE || + handled_fanout == + (prev_dups_producing_tables ^ dups_producing_tables)) + { + prev_strategy= strategy; + if (pos->sj_strategy == SJ_OPT_NONE) + { + prev_dups_producing_tables= dups_producing_tables; + prev_sjm_lookup_tables= join->sjm_lookup_tables; + } + /* Mark strategy as used */ + (*strategy)->mark_used(); + pos->sj_strategy= sj_strategy; + if (sj_strategy == SJ_OPT_MATERIALIZE) + join->sjm_lookup_tables |= handled_fanout; + else + join->sjm_lookup_tables &= ~handled_fanout; + *current_read_time= read_time; + *current_record_count= rec_count; + dups_producing_tables &= ~handled_fanout; + //TODO: update bitmap of semi-joins that were handled together with + // others. + if (is_multiple_semi_joins(join, join->positions, idx, + handled_fanout)) + pos->inner_tables_handled_with_other_sjs |= handled_fanout; + } else - join->sjm_lookup_tables &= ~handled_fanout; - *current_read_time= read_time; - *current_record_count= rec_count; - dups_producing_tables &= ~handled_fanout; - //TODO: update bitmap of semi-joins that were handled together with - // others. - if (is_multiple_semi_joins(join, join->positions, idx, handled_fanout)) - pos->inner_tables_handled_with_other_sjs |= handled_fanout; + { + /* Conflict fall to most general variant */ + (*prev_strategy)->set_empty(); + dups_producing_tables= prev_dups_producing_tables; + join->sjm_lookup_tables= prev_sjm_lookup_tables; + // mark it 'none' to avpoid loops + pos->sj_strategy= SJ_OPT_NONE; + // next skip to last; + strategy= pickers + + (sizeof(pickers)/sizeof(Semi_join_strategy_picker*) - 3); + continue; + } } else { diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 0236f98c886..52bda560c1c 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -2747,6 +2747,24 @@ end: DBUG_RETURN(result); } + +bool partition_info::error_if_requires_values() const +{ + switch (part_type) { + case NOT_A_PARTITION: + case HASH_PARTITION: + break; + case RANGE_PARTITION: + my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "RANGE", "LESS THAN"); + return true; + case LIST_PARTITION: + my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "LIST", "IN"); + return true; + } + return false; +} + + /** Fix partition data from parser. @@ -2836,6 +2854,8 @@ bool partition_info::fix_parser_data(THD *thd) part_elem= it++; List_iterator<part_elem_value> list_val_it(part_elem->list_val_list); num_elements= part_elem->list_val_list.elements; + if (!num_elements && error_if_requires_values()) + DBUG_RETURN(true); DBUG_ASSERT(part_type == RANGE_PARTITION ? num_elements == 1U : TRUE); for (j= 0; j < num_elements; j++) diff --git a/sql/partition_info.h b/sql/partition_info.h index a80295edde0..f250c5496bf 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -368,6 +368,7 @@ public: bool *prune_needs_default_values, MY_BITMAP *used_partitions); bool has_same_partitioning(partition_info *new_part_info); + bool error_if_requires_values() const; private: static int list_part_cmp(const void* a, const void* b); bool set_up_default_partitions(handler *file, HA_CREATE_INFO *info, diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index de0daf759fe..4958473c73d 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -1735,29 +1735,29 @@ ER_WRONG_AUTO_KEY 42000 S1009 ER_UNUSED_9 eng "You should never see it" ER_NORMAL_SHUTDOWN - cze "%s: normální ukončení\n" - dan "%s: Normal nedlukning\n" - nla "%s: Normaal afgesloten \n" - eng "%s: Normal shutdown\n" - est "%s: MariaDB lõpetas\n" - fre "%s: Arrêt normal du serveur\n" - ger "%s: Normal heruntergefahren\n" - greek "%s: Φυσιολογική διαδικασία shutdown\n" - hun "%s: Normal leallitas\n" - ita "%s: Shutdown normale\n" - jpn "%s: 通常シャットダウン\n" - kor "%s: 정상적인 shutdown\n" - nor "%s: Normal avslutning\n" - norwegian-ny "%s: Normal nedkopling\n" - pol "%s: Standardowe zakończenie działania\n" - por "%s: 'Shutdown' normal\n" - rum "%s: Terminare normala\n" - rus "%s: Корректная остановка\n" - serbian "%s: Normalno gašenje\n" - slo "%s: normálne ukončenie\n" - spa "%s: Apagado normal\n" - swe "%s: Normal avslutning\n" - ukr "%s: Нормальне завершення\n" + cze "%s: norm-Bální ukončení" + dan "%s: Normal nedlukning" + nla "%s: Normaal afgesloten" + eng "%s: Normal shutdown" + est "%s: MariaDB lõpetas" + fre "%s: Arrêt normal du serveur" + ger "%s: Normal heruntergefahren" + greek "%s: Φυσιολογική διαδικασία shutdown" + hun "%s: Normal leallitas" + ita "%s: Shutdown normale" + jpn "%s: 通常シャットダウン" + kor "%s: 정상적인 shutdown" + nor "%s: Normal avslutning" + norwegian-ny "%s: Normal nedkopling" + pol "%s: Standardowe zakończenie działania" + por "%s: 'Shutdown' normal" + rum "%s: Terminare normala" + rus "%s: Корректная остановка" + serbian "%s: Normalno gašenje" + slo "%s: normálne ukončenie" + spa "%s: Apagado normal" + swe "%s: Normal avslutning" + ukr "%s: Нормальне завершення" ER_GOT_SIGNAL cze "%s: přijat signal %d, končím\n" dan "%s: Fangede signal %d. Afslutter!!\n" diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index c9a031db911..f08bd8a564d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2129,37 +2129,42 @@ static void acl_insert_user(const char *user, const char *host, } -static void acl_update_db(const char *user, const char *host, const char *db, +static bool acl_update_db(const char *user, const char *host, const char *db, ulong privileges) { mysql_mutex_assert_owner(&acl_cache->lock); + bool updated= false; + for (uint i=0 ; i < acl_dbs.elements ; i++) { ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*); if ((!acl_db->user && !user[0]) || - (acl_db->user && - !strcmp(user,acl_db->user))) + (acl_db->user && + !strcmp(user,acl_db->user))) { if ((!acl_db->host.hostname && !host[0]) || - (acl_db->host.hostname && - !strcmp(host, acl_db->host.hostname))) + (acl_db->host.hostname && + !strcmp(host, acl_db->host.hostname))) { - if ((!acl_db->db && !db[0]) || - (acl_db->db && !strcmp(db,acl_db->db))) + if ((!acl_db->db && !db[0]) || + (acl_db->db && !strcmp(db,acl_db->db))) - { - if (privileges) + { + if (privileges) { acl_db->access= privileges; acl_db->initial_access= acl_db->access; } - else - delete_dynamic_element(&acl_dbs,i); - } + else + delete_dynamic_element(&acl_dbs,i); + updated= true; + } } } } + + return updated; } @@ -3468,9 +3473,21 @@ static int replace_db_table(TABLE *table, const char *db, acl_cache->clear(1); // Clear privilege cache if (old_row_exists) acl_update_db(combo.user.str,combo.host.str,db,rights); - else - if (rights) - acl_insert_db(combo.user.str,combo.host.str,db,rights); + else if (rights) + { + /* + If we did not have an already existing row, for users, we must always + insert an ACL_DB entry. For roles however, it is possible that one was + already created when DB privileges were propagated from other granted + roles onto the current role. For this case, first try to update the + existing entry, otherwise insert a new one. + */ + if (!combo.is_role() || + !acl_update_db(combo.user.str, combo.host.str, db, rights)) + { + acl_insert_db(combo.user.str,combo.host.str,db,rights); + } + } DBUG_RETURN(0); /* This could only happen if the grant tables got corrupted */ @@ -5385,9 +5402,12 @@ static int merge_role_privileges(ACL_ROLE *role __attribute__((unused)), { PRIVS_TO_MERGE *data= (PRIVS_TO_MERGE *)context; + DBUG_ASSERT(grantee->counter > 0); if (--grantee->counter) return 1; // don't recurse into grantee just yet + grantee->counter= 1; // Mark the grantee as merged. + /* if we'll do db/table/routine privileges, create a hash of role names */ role_hash_t role_hash(role_key); if (data->what != PRIVS_TO_MERGE::GLOBAL) @@ -6577,10 +6597,10 @@ end_index_init: DBUG_RETURN(return_val); } - -my_bool role_propagate_grants_action(void *ptr, void *unused __attribute__((unused))) +static my_bool propagate_role_grants_action(void *role_ptr, + void *ptr __attribute__((unused))) { - ACL_ROLE *role= (ACL_ROLE *)ptr; + ACL_ROLE *role= static_cast<ACL_ROLE *>(role_ptr); if (role->counter) return 0; @@ -6637,7 +6657,7 @@ my_bool grant_reload(THD *thd) obtaining LOCK_grant rwlock. */ if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) - goto end; + DBUG_RETURN(1); mysql_rwlock_wrlock(&LOCK_grant); grant_version++; @@ -6669,14 +6689,13 @@ my_bool grant_reload(THD *thd) } mysql_mutex_lock(&acl_cache->lock); - my_hash_iterate(&acl_roles, role_propagate_grants_action, NULL); + my_hash_iterate(&acl_roles, propagate_role_grants_action, NULL); mysql_mutex_unlock(&acl_cache->lock); mysql_rwlock_unlock(&LOCK_grant); close_mysql_tables(thd); -end: DBUG_RETURN(return_val); } diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index ead77480f34..c5e11b7f4c1 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -638,8 +638,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, */ if (lock_type == TL_WRITE && !table->table->s->tmp_table) { - 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 d52d50d2c9c..e2607dea28f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -9151,7 +9151,17 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) DBUG_PRINT("info",("Performing FULLTEXT search")); while ((ifm=li++)) - ifm->init_search(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(no_order); + } return 0; } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 2e9e90346fb..e0818da325a 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1191,7 +1191,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) @@ -1563,6 +1567,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); } @@ -1799,7 +1805,7 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length) sql++; continue; } - /* fall trough */ + /* fall through */ default: break; } @@ -2761,13 +2767,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) @@ -2775,6 +2785,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 c7b55aa9b68..2502962cef0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2670,6 +2670,8 @@ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value, MEM_ROOT *runtime_memroot) { Item_change_record *change; + DBUG_ENTER("THD::nocheck_register_item_tree_change"); + DBUG_PRINT("enter", ("Register %p <- %p", old_value, (*place))); /* Now we use one node per change, which adds some memory overhead, but still is rather fast as we use alloc_root for allocations. @@ -2682,12 +2684,13 @@ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value, OOM, thd->fatal_error() is called by the error handler of the memroot. Just return. */ - return; + DBUG_VOID_RETURN; } change= new (change_mem) Item_change_record; change->place= place; change->old_value= old_value; change_list.append(change); + DBUG_VOID_RETURN; } /** @@ -2709,6 +2712,9 @@ void THD::check_and_register_item_tree_change(Item **place, Item **new_value, 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++)) { @@ -2718,6 +2724,7 @@ void THD::check_and_register_item_tree_change(Item **place, Item **new_value, if (change) nocheck_register_item_tree_change(place, change->old_value, runtime_memroot); + DBUG_VOID_RETURN; } @@ -2725,13 +2732,13 @@ void THD::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++)) + { *change->place= change->old_value; + } /* We can forget about changes memory: it's allocated in runtime memroot */ change_list.empty(); - DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 1968b45c1ee..0721252193d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1118,6 +1118,30 @@ typedef struct st_xid_state { bool in_thd; /* Error reported by the Resource Manager (RM) to the Transaction Manager. */ uint rm_error; + + /** + 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; extern mysql_mutex_t LOCK_xid_cache; @@ -3267,10 +3291,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_cursor.cc b/sql/sql_cursor.cc index d8684086e68..ff06d67fc29 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -210,7 +210,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 4578bcec394..7ad0b4b4c69 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -362,9 +362,16 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) SELECT_LEX *parent_lex= derived->select_lex; Query_arena *arena, backup; DBUG_ENTER("mysql_derived_merge"); + 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 (dt_select->uncacheable & UNCACHEABLE_RAND) { @@ -466,7 +473,8 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) // Update used tables cache according to new table map if (derived->on_expr) { - derived->on_expr->fix_after_pullout(parent_lex, &derived->on_expr); + derived->on_expr->fix_after_pullout(parent_lex, &derived->on_expr, + TRUE); fix_list_after_tbl_changes(parent_lex, &derived->nested_join->join_list); } } @@ -509,7 +517,9 @@ unconditional_materialization: bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived) { DBUG_ENTER("mysql_derived_merge_for_insert"); - DBUG_PRINT("enter", ("derived: %p", derived)); + DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", + (derived->alias ? derived->alias : "<NULL>"), + derived->get_unit())); DBUG_PRINT("info", ("merged_for_insert: %d is_materialized_derived: %d " "is_multitable: %d single_table_updatable: %d " "merge_underlying_list: %d", @@ -565,7 +575,9 @@ bool mysql_derived_init(THD *thd, LEX *lex, TABLE_LIST *derived) { SELECT_LEX_UNIT *unit= derived->get_unit(); DBUG_ENTER("mysql_derived_init"); - DBUG_PRINT("enter", ("derived: %p", derived)); + DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", + (derived->alias ? derived->alias : "<NULL>"), + derived->get_unit())); // Skip already prepared views/DT if (!unit || unit->prepared) @@ -636,7 +648,9 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived) SELECT_LEX_UNIT *unit= derived->get_unit(); DBUG_ENTER("mysql_derived_prepare"); bool res= FALSE; - DBUG_PRINT("enter", ("unit 0x%lx", (ulong) unit)); + DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", + (derived->alias ? derived->alias : "<NULL>"), + unit)); // Skip already prepared views/DT if (!unit || unit->prepared || @@ -668,6 +682,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 select_union)) @@ -794,6 +819,14 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) bool res= FALSE; DBUG_ENTER("mysql_derived_optimize"); + 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); @@ -859,6 +892,9 @@ err: bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived) { DBUG_ENTER("mysql_derived_create"); + DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", + (derived->alias ? derived->alias : "<NULL>"), + derived->get_unit())); TABLE *table= derived->table; SELECT_LEX_UNIT *unit= derived->get_unit(); @@ -908,9 +944,13 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived) bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) { - DBUG_ENTER("mysql_derived_fill"); + Field_iterator_table field_iterator; SELECT_LEX_UNIT *unit= derived->get_unit(); bool res= FALSE; + DBUG_ENTER("mysql_derived_fill"); + DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", + (derived->alias ? derived->alias : "<NULL>"), + derived->get_unit())); if (unit->executed && !unit->uncacheable && !unit->describe) DBUG_RETURN(FALSE); @@ -950,7 +990,27 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) if (derived_result->flush()) res= TRUE; unit->executed= TRUE; + + if (derived->field_translation) + { + /* reset translation table to materialized table */ + field_iterator.set_table(derived->table); + for (uint i= 0; + !field_iterator.end_of_fields(); + field_iterator.next(), i= i + 1) + { + Item *item; + + if (!(item= field_iterator.create_item(thd))) + { + res= TRUE; + break; + } + thd->change_item_tree(&derived->field_translation[i].item, item); + } + } } + if (res || !lex->describe) unit->cleanup(); lex->current_select= save_current_select; @@ -979,6 +1039,9 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived) { DBUG_ENTER("mysql_derived_reinit"); + DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", + (derived->alias ? derived->alias : "<NULL>"), + derived->get_unit())); st_select_lex_unit *unit= derived->get_unit(); derived->merged_for_insert= FALSE; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 201afbf3f2a..af0321ce68f 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, 2016, 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 7584b42c904..41f1c3e9e65 100644 --- a/sql/sql_join_cache.cc +++ b/sql/sql_join_cache.cc @@ -394,7 +394,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 92fec3e1ec1..e0b14e536c0 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 diff --git a/sql/sql_lex.h b/sql/sql_lex.h index c9ce84e51c0..3fed9808f57 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, 2016, 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 @@ -477,7 +477,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. @@ -2959,7 +2959,7 @@ struct st_lex_local: public LEX return (void*) alloc_root(mem_root, (uint) size); } static void operator delete(void *ptr,size_t size) - { TRASH(ptr, size); } + { TRASH_FREE(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) { /* Never called */ } }; diff --git a/sql/sql_lifo_buffer.h b/sql/sql_lifo_buffer.h index feec4aeb4c2..f551cc48c23 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 7538f69766d..08667bed02a 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -41,12 +41,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; inline Sql_alloc() :dummy(0) {} diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 02109b22898..dd1f60ec078 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4886,16 +4886,11 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "LIST", "IN"); } - else if (tab_part_info->part_type == RANGE_PARTITION) - { - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); - } else { - DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION); - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "LIST", "IN"); + DBUG_ASSERT(tab_part_info->part_type == RANGE_PARTITION || + tab_part_info->part_type == LIST_PARTITION); + (void) tab_part_info->error_if_requires_values(); } goto err; } @@ -6834,10 +6829,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, lpt->part_info= part_info; lpt->alter_info= alter_info; lpt->create_info= create_info; - lpt->db_options= create_info->table_options; - if (create_info->row_type != ROW_TYPE_FIXED && - create_info->row_type != ROW_TYPE_DEFAULT) - lpt->db_options|= HA_OPTION_PACK_RECORD; + lpt->db_options= create_info->table_options_with_row_type(); lpt->table= table; lpt->key_info_buffer= 0; lpt->key_count= 0; diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 9e016019d10..013e00faeb9 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -260,7 +260,7 @@ public: static void *operator new(size_t size, MEM_ROOT *mem_root) { return (void*) alloc_root(mem_root, size); } static void operator delete(void *ptr_arg,size_t size) - { TRASH(ptr_arg, size); } + { TRASH_FREE(ptr_arg, size); } sys_var_pluginvar(sys_var_chain *chain, const char *name_arg, struct st_mysql_sys_var *plugin_var_arg, @@ -467,6 +467,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_select.cc b/sql/sql_select.cc index 3c2b62a6540..fd8ff6eb016 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,11 @@ enum enum_exec_or_opt {WALK_OPTIMIZATION_TABS , WALK_EXECUTION_TABS}; JOIN_TAB *first_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind); JOIN_TAB *next_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind, JOIN_TAB *tab); +static bool +find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, + ORDER *order, List<Item> &fields, List<Item> &all_fields, + bool is_group_field, bool add_to_all_fields); + static double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s, table_map rem_tables); @@ -333,7 +338,6 @@ bool dbug_user_var_equals_int(THD *thd, const char *name, int value) } #endif - /** This handles SELECT with and without UNION. */ @@ -697,6 +701,9 @@ JOIN::prepare(Item ***rref_pointer_array, 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); @@ -759,12 +766,11 @@ JOIN::prepare(Item ***rref_pointer_array, } table_count= select_lex->leaf_tables.elements; - + TABLE_LIST *tbl; List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables); while ((tbl= li++)) { - //table_count++; /* Count the number of tables in the join. */ /* If the query uses implicit grouping where the select list contains both aggregate functions and non-aggregate fields, any non-aggregated field @@ -799,9 +805,15 @@ JOIN::prepare(Item ***rref_pointer_array, /* Resolve the ORDER BY that was skipped, then remove it. */ if (skip_order_by && select_lex != select_lex->master_unit()->global_parameters) { - if (setup_order(thd, (*rref_pointer_array), 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, *rref_pointer_array, tables_list, order, + fields_list, all_fields, false, false)) + DBUG_RETURN(-1); + } select_lex->order_list.empty(); } @@ -2208,8 +2220,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) @@ -10239,7 +10254,7 @@ void JOIN::drop_unused_derived_keys() table->use_index(tab->ref.key); if (table->s->keys) { - if (tab->ref.key >= 0) + if (tab->ref.key >= 0 && tab->ref.key < MAX_KEY) tab->ref.key= 0; else table->s->keys= 0; @@ -12049,8 +12064,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 ) @@ -12355,7 +12370,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; @@ -15189,14 +15204,14 @@ internal_remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) */ Item **args= ((Item_func_isnull*) cond)->arguments(); - Field *field=((Item_field*) args[0])->field; + Field *field=((Item_field*) (args[0]->real_item()))->field; Item *item0= new(thd->mem_root) Item_int((longlong)0, 1); Item *eq_cond= new(thd->mem_root) Item_func_eq(args[0], item0); if (!eq_cond) return cond; - if (field->table->pos_in_table_list->is_inner_table_of_outer_join()) + if (field->table->pos_in_table_list->is_inner_table_of_outer_join()) { // outer join: transform "col IS NULL" to "col IS NULL or col=0" Item *or_cond= new(thd->mem_root) Item_cond_or(eq_cond, cond); @@ -16430,7 +16445,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, else { field->set_notnull(); - memcpy(field->ptr, orig_field->ptr, field->pack_length()); + memcpy(field->ptr, orig_field->ptr, field->pack_length_in_rec()); } orig_field->move_field_offset(-diff); // Back to record[0] } @@ -21457,7 +21472,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. @retval FALSE if OK @@ -21468,7 +21486,7 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref) static bool find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, ORDER *order, List<Item> &fields, List<Item> &all_fields, - bool is_group_field) + bool is_group_field, bool add_to_all_fields) { Item *order_item= *order->item; /* The item from the GROUP/ORDER caluse. */ Item::Type order_item_type; @@ -21588,6 +21606,9 @@ find_order_in_list(THD *thd, Item **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; DBUG_ASSERT(all_fields.elements <= thd->lex->current_select->ref_pointer_array_size); @@ -21617,13 +21638,13 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, */ int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, - List<Item> &fields, List<Item> &all_fields, ORDER *order) + List<Item> &fields, List<Item> &all_fields, ORDER *order) { thd->where="order clause"; for (; order; order=order->next) { if (find_order_in_list(thd, ref_pointer_array, tables, order, fields, - all_fields, FALSE)) + all_fields, FALSE, true)) return 1; } return 0; @@ -21675,7 +21696,7 @@ setup_group(THD *thd, Item **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)) + all_fields, TRUE, true)) return 1; (*ord->item)->marker= UNDEF_POS; /* Mark found */ if ((*ord->item)->with_sum_func) @@ -21994,6 +22015,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 diff --git a/sql/sql_select.h b/sql/sql_select.h index 4f1b7bd7e05..f000ce3ba74 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1770,7 +1770,7 @@ int get_quick_record(SQL_SELECT *select); SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length, SORT_FIELD *sortorder); int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, - List<Item> &fields, List <Item> &all_fields, ORDER *order); + List<Item> &fields, List <Item> &all_fields, ORDER *order); int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, List<Item> &fields, List<Item> &all_fields, ORDER *order, bool *hidden_group_fields); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0439b94df88..6bbb94ecac6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2264,7 +2264,7 @@ public: } static void operator delete(void *ptr __attribute__((unused)), size_t size __attribute__((unused))) - { TRASH(ptr, size); } + { TRASH_FREE(ptr, size); } ulong thread_id; time_t start_time; diff --git a/sql/sql_string.h b/sql/sql_string.h index 557d14a79f8..d60280a75ed 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -112,7 +112,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 52c252e2259..821badb0147 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1830,7 +1830,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, @@ -4417,10 +4418,7 @@ handler *mysql_create_frm_image(THD *thd, set_table_default_charset(thd, create_info, (char*) db); - db_options= create_info->table_options; - if (create_info->row_type == ROW_TYPE_DYNAMIC || - create_info->row_type == ROW_TYPE_PAGE) - db_options|= HA_OPTION_PACK_RECORD; + db_options= create_info->table_options_with_row_type(); if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, create_info->db_type))) @@ -8940,7 +8938,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, TODO don't create the frm in the first place */ - deletefrm(alter_ctx.get_tmp_path()); + const char *path= alter_ctx.get_tmp_path(); + table->file->ha_create_partitioning_metadata(path, NULL, CHF_DELETE_FLAG); + deletefrm(path); my_free(const_cast<uchar*>(frm.str)); goto end_inplace; } @@ -9712,12 +9712,13 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, if ((int) key_nr >= 0) { const char *err_msg= ER(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(ER_DUP_ENTRY_AUTOINCREMENT_CASE); - print_keydup_error(to, key_nr == MAX_KEY ? NULL : - &to->key_info[key_nr], + print_keydup_error(to, + key_nr >= to->s->keys ? NULL : + &to->key_info[key_nr], err_msg, MYF(0)); } else diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 16de451211f..01de3098783 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -941,22 +941,6 @@ bool st_select_lex_unit::cleanup() void st_select_lex_unit::reinit_exec_mechanism() { prepared= optimized= executed= 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 } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7e41f05fc56..aea37a9d14f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5126,18 +5126,8 @@ opt_part_values: partition_info *part_info= lex->part_info; if (! lex->is_partition_management()) { - if (part_info->part_type == RANGE_PARTITION) - { - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); - MYSQL_YYABORT; - } - if (part_info->part_type == LIST_PARTITION) - { - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "LIST", "IN"); - MYSQL_YYABORT; - } + if (part_info->error_if_requires_values()) + MYSQL_YYABORT; } else part_info->part_type= HASH_PARTITION; diff --git a/sql/structs.h b/sql/structs.h index ee61b8d3b3a..e141a8d7668 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -191,7 +191,7 @@ typedef int *(*update_var)(THD *, struct st_mysql_show_var *); typedef struct st_lex_user { LEX_STRING user, host, password, plugin, auth; - bool is_role() { return user.str[0] && !host.str[0]; } + bool is_role() const { return user.str[0] && !host.str[0]; } void set_lex_string(LEX_STRING *l, char *buf) { if (is_role()) diff --git a/sql/table.cc b/sql/table.cc index c1283008513..1ab57e6e37c 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1316,9 +1316,10 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, extra_rec_buf_length= uint2korr(frm_image+59); rec_buff_length= ALIGN_SIZE(share->reclength + 1 + extra_rec_buf_length); 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); @@ -2609,6 +2610,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) { @@ -2623,6 +2625,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)* @@ -4058,7 +4062,7 @@ void TABLE::init(THD *thd, TABLE_LIST *tl) DBUG_ASSERT(key_read == 0); /* mark the record[0] uninitialized */ - TRASH(record[0], s->reclength); + TRASH_ALLOC(record[0], s->reclength); /* Initialize the null marker bits, to ensure that if we are doing a read @@ -4176,6 +4180,9 @@ bool TABLE_LIST::create_field_translation(THD *thd) Query_arena *arena, backup; bool res= FALSE; DBUG_ENTER("TABLE_LIST::create_field_translation"); + DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", + (alias ? alias : "<NULL>"), + get_unit())); if (thd->stmt_arena->is_conventional() || thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) @@ -6126,6 +6133,14 @@ void TABLE::create_key_part_by_field(KEY_PART_INFO *key_part_info, might be reused. */ key_part_info->store_length= key_part_info->length; + /* + For BIT fields null_bit is not set to 0 even if the field is defined + as NOT NULL, look at Field_bit::Field_bit + */ + if (!field->real_maybe_null()) + { + key_part_info->null_bit= 0; + } /* The total store length of the key part is the raw length of the field + diff --git a/sql/table.h b/sql/table.h index 0c5e00cc34d..69a954e73d3 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2206,6 +2206,9 @@ struct TABLE_LIST inline void set_merged_derived() { DBUG_ENTER("set_merged_derived"); + DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", + (alias ? alias : "<NULL>"), + get_unit())); derived_type= ((derived_type & DTYPE_MASK) | DTYPE_TABLE | DTYPE_MERGE); set_check_merged(); @@ -2218,6 +2221,9 @@ struct TABLE_LIST void set_materialized_derived() { DBUG_ENTER("set_materialized_derived"); + DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", + (alias ? alias : "<NULL>"), + get_unit())); derived_type= ((derived_type & (derived ? DTYPE_MASK : DTYPE_VIEW)) | DTYPE_TABLE | DTYPE_MATERIALIZE); set_check_materialized(); diff --git a/sql/transaction.cc b/sql/transaction.cc index f478b4a18f7..1a98b54edef 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -532,12 +532,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); @@ -612,12 +608,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 12d3c265a86..90e55fea30c 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 @@ -83,7 +83,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 @@ -156,7 +156,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, @@ -246,6 +247,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); |