diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2018-02-15 10:22:03 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2018-02-15 10:22:03 +0200 |
commit | b006d2ead4640f0ab4e29687fd7d24988b1c98f1 (patch) | |
tree | a478984bcd7f4bb2e0fd0496eae77b871077a380 /sql | |
parent | b782971c58b5656820429b8ef3fae5fd82f5a0f7 (diff) | |
parent | dc09f8f29cb2b9fdce7d5d5a623fdc8dcf1814f9 (diff) | |
download | mariadb-git-b006d2ead4640f0ab4e29687fd7d24988b1c98f1.tar.gz |
Merge bb-10.2-ext into 10.3
Diffstat (limited to 'sql')
79 files changed, 1274 insertions, 573 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index bb344f5a9ee..c7c4df279e7 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 19bca942082..7c88f230734 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) { @@ -5828,6 +5828,13 @@ static void calc_datetime_days_diff(MYSQL_TIME *ltime, long days) ltime->second) * 1000000LL + ltime->second_part); unpack_time(timediff, ltime); + /* + unpack_time() broke down hours into ltime members hour,day,month. + Mix them back to ltime->hour using the same factors + that pack_time()/unpack_time() use (i.e. 32 for month). + */ + ltime->hour+= (ltime->month * 32 + ltime->day) * 24; + ltime->month= ltime->day= 0; } ltime->time_type= MYSQL_TIMESTAMP_TIME; } @@ -9759,7 +9766,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 8a9775cd9d5..364e937227c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -642,7 +642,7 @@ public: DBUG_ASSERT(size < UINT_MAX32); return thd_alloc(current_thd, (uint) 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 4ab0f330814..d648c90e114 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -610,7 +610,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; @@ -658,9 +658,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/ha_partition.cc b/sql/ha_partition.cc index 48bfd471e67..4ec6f3dfa38 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -89,7 +89,7 @@ static handler *partition_create_handler(handlerton *hton, TABLE_SHARE *share, MEM_ROOT *mem_root); static uint partition_flags(); -static uint alter_table_flags(uint flags); +static ulonglong alter_table_flags(ulonglong flags); /* If frm_error() is called then we will use this to to find out what file @@ -214,7 +214,7 @@ static uint partition_flags() return HA_CAN_PARTITION; } -static uint alter_table_flags(uint flags __attribute__((unused))) +static ulonglong alter_table_flags(ulonglong /* flags */) { return (HA_PARTITION_FUNCTION_SUPPORTED | HA_FAST_CHANGE_PARTITION); @@ -8339,6 +8339,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_STATS *stat_info, stat_info->data_file_length= file->stats.data_file_length; stat_info->max_data_file_length= file->stats.max_data_file_length; stat_info->index_file_length= file->stats.index_file_length; + stat_info->max_index_file_length= file->stats.max_index_file_length; stat_info->delete_length= file->stats.delete_length; stat_info->create_time= file->stats.create_time; stat_info->update_time= file->stats.update_time; @@ -9778,9 +9779,9 @@ handler::Table_flags ha_partition::table_flags() const alter_table_flags must be on handler/table level, not on hton level due to the ha_partition hton does not know what the underlying hton is. */ -uint ha_partition::alter_table_flags(uint flags) +ulonglong ha_partition::alter_table_flags(ulonglong flags) { - uint flags_to_return; + ulonglong flags_to_return; DBUG_ENTER("ha_partition::alter_table_flags"); flags_to_return= ht->alter_table_flags(flags); diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 1a6bdc35346..30dd24b6014 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1189,7 +1189,7 @@ public: wrapper function for handlerton alter_table_flags, since the ha_partition_hton cannot know all its capabilities */ - virtual uint alter_table_flags(uint flags); + virtual ulonglong alter_table_flags(ulonglong flags); /* unireg.cc will call the following to make sure that the storage engine can handle the data it is about to send. diff --git a/sql/handler.cc b/sql/handler.cc index f93c5624d80..0534a701b73 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3490,9 +3490,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 { @@ -3593,11 +3595,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; } } @@ -4727,6 +4727,7 @@ void handler::get_dynamic_partition_info(PARTITION_STATS *stat_info, stat_info->data_file_length= stats.data_file_length; stat_info->max_data_file_length= stats.max_data_file_length; stat_info->index_file_length= stats.index_file_length; + stat_info->max_index_file_length=stats.max_index_file_length; stat_info->delete_length= stats.delete_length; stat_info->create_time= stats.create_time; stat_info->update_time= stats.update_time; diff --git a/sql/handler.h b/sql/handler.h index 8fe42ea210a..a96e98c2f84 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1249,7 +1249,7 @@ struct handlerton bool (*flush_logs)(handlerton *hton); bool (*show_status)(handlerton *hton, THD *thd, stat_print_fn *print, enum ha_stat_type stat); uint (*partition_flags)(); - uint (*alter_table_flags)(uint flags); + ulonglong (*alter_table_flags)(ulonglong flags); int (*alter_tablespace)(handlerton *hton, THD *thd, st_alter_tablespace *ts_info); int (*fill_is_table)(handlerton *hton, THD *thd, TABLE_LIST *tables, class Item *cond, @@ -1678,6 +1678,7 @@ typedef struct { ulonglong data_file_length; ulonglong max_data_file_length; ulonglong index_file_length; + ulonglong max_index_file_length; ulonglong delete_length; ha_rows records; ulong mean_rec_length; @@ -2728,9 +2729,10 @@ public: ha_statistics(): data_file_length(0), max_data_file_length(0), - index_file_length(0), delete_length(0), auto_increment_value(0), - records(0), deleted(0), mean_rec_length(0), create_time(0), - check_time(0), update_time(0), block_size(0), mrr_length_per_rec(0) + index_file_length(0), max_index_file_length(0), delete_length(0), + auto_increment_value(0), records(0), deleted(0), mean_rec_length(0), + create_time(0), check_time(0), update_time(0), block_size(0), + mrr_length_per_rec(0) {} }; @@ -4259,7 +4261,7 @@ public: but we don't have a primary key */ virtual void use_hidden_primary_key(); - virtual uint alter_table_flags(uint flags) + virtual ulonglong alter_table_flags(ulonglong flags) { if (ht->alter_table_flags) return ht->alter_table_flags(flags); diff --git a/sql/item.cc b/sql/item.cc index 855cb954301..34db1a80dcd 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 @@ -887,6 +887,34 @@ bool Item_field::add_field_to_set_processor(void *arg) DBUG_RETURN(FALSE); } + +/** + Rename fields in an expression to new field name as speficied by ALTER TABLE +*/ + +bool Item_field::rename_fields_processor(void *arg) +{ + Item::func_processor_rename *rename= (Item::func_processor_rename*) arg; + List_iterator<Create_field> def_it(rename->fields); + Create_field *def; + + while ((def=def_it++)) + { + if (def->change.str && + (!db_name || !db_name[0] || + !my_strcasecmp(table_alias_charset, db_name, rename->db_name.str)) && + (!table_name || !table_name[0] || + !my_strcasecmp(table_alias_charset, table_name, rename->table_name.str)) && + !my_strcasecmp(system_charset_info, field_name.str, def->change.str)) + { + field_name= def->field_name; + break; + } + } + return 0; +} + + /** Check if an Item_field references some field from a list of fields. @@ -1431,67 +1459,73 @@ Item *Item_param::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) As a extra convenience the time structure is reset on error or NULL values! */ -bool Item::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) +bool Item::get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate) { - if (field_type() == MYSQL_TYPE_TIME) - fuzzydate|= TIME_TIME_ONLY; + longlong value= val_int(); + bool neg= !unsigned_flag && value < 0; + if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value, + ltime, fuzzydate, + field_name_or_null())) + return null_value|= make_zero_date(ltime, fuzzydate); + return null_value= false; +} - switch (result_type()) { - case INT_RESULT: - { - longlong value= val_int(); - bool neg= !unsigned_flag && value < 0; - if (field_type() == MYSQL_TYPE_YEAR) - { - if (max_length == 2) - { - if (value < 70) - value+= 2000; - else if (value <= 1900) - value+= 1900; - } - value*= 10000; /* make it YYYYMMHH */ - } - if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value, - ltime, fuzzydate, - field_name_or_null())) - goto err; - break; - } - case REAL_RESULT: - { - double value= val_real(); - if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate, - field_name_or_null())) - goto err; - break; - } - case DECIMAL_RESULT: - { - my_decimal value, *res; - if (!(res= val_decimal(&value)) || - decimal_to_datetime_with_warn(res, ltime, fuzzydate, - field_name_or_null())) - goto err; - break; - } - case STRING_RESULT: + +bool Item::get_date_from_year(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + longlong value= val_int(); + DBUG_ASSERT(unsigned_flag || value >= 0); + if (max_length == 2) { - char buff[40]; - String tmp(buff,sizeof(buff), &my_charset_bin),*res; - if (!(res=val_str(&tmp)) || - str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(), - ltime, fuzzydate)) - goto err; - break; - } - default: - DBUG_ASSERT(0); + if (value < 70) + value+= 2000; + else if (value <= 1900) + value+= 1900; } + value*= 10000; /* make it YYYYMMHH */ + if (null_value || int_to_datetime_with_warn(false, value, + ltime, fuzzydate, + field_name_or_null())) + return null_value|= make_zero_date(ltime, fuzzydate); + return null_value= false; +} - return null_value= 0; -err: +bool Item::get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + double value= val_real(); + if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate, + field_name_or_null())) + return null_value|= make_zero_date(ltime, fuzzydate); + return null_value= false; +} + + +bool Item::get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + my_decimal value, *res; + if (!(res= val_decimal(&value)) || + decimal_to_datetime_with_warn(res, ltime, fuzzydate, + field_name_or_null())) + return null_value|= make_zero_date(ltime, fuzzydate); + return null_value= false; +} + + +bool Item::get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + char buff[40]; + String tmp(buff,sizeof(buff), &my_charset_bin),*res; + if (!(res=val_str(&tmp)) || + str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(), + ltime, fuzzydate)) + return null_value|= make_zero_date(ltime, fuzzydate); + return null_value= false; +} + + +bool Item::make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ /* if the item was not null and convertion failed, we return a zero date if allowed, otherwise - null. @@ -1513,7 +1547,7 @@ err: */ ltime->time_type= MYSQL_TIMESTAMP_TIME; } - return null_value|= !(fuzzydate & TIME_FUZZY_DATES); + return !(fuzzydate & TIME_FUZZY_DATES); } bool Item::get_seconds(ulonglong *sec, ulong *sec_part) @@ -1757,6 +1791,16 @@ my_decimal *Item_sp_variable::val_decimal(my_decimal *decimal_value) } +bool Item_sp_variable::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + DBUG_ASSERT(fixed); + Item *it= this_item(); + bool val= it->get_date(ltime, fuzzydate); + null_value= it->null_value; + return val; +} + + bool Item_sp_variable::is_null() { return this_item()->is_null(); @@ -2102,6 +2146,13 @@ my_decimal *Item_name_const::val_decimal(my_decimal *decimal_value) return val; } +bool Item_name_const::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + DBUG_ASSERT(fixed); + bool rc= value_item->get_date(ltime, fuzzydate); + null_value= value_item->null_value; + return rc; +} bool Item_name_const::is_null() { @@ -3955,6 +4006,15 @@ my_decimal *Item_null::val_decimal(my_decimal *decimal_value) } +bool Item_null::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + // following assert is redundant, because fixed=1 assigned in constructor + DBUG_ASSERT(fixed == 1); + make_zero_date(ltime, fuzzydate); + return (null_value= true); +} + + Item *Item_null::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) { return this; @@ -4425,7 +4485,7 @@ bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate) *res= value.time; return 0; } - return Item::get_date(res, fuzzydate); + return type_handler()->Item_get_date(this, res, fuzzydate); } @@ -9430,7 +9490,7 @@ bool Item_ignore_value::send(Protocol *protocol, st_value *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); } @@ -10441,6 +10501,12 @@ String *Item_type_holder::val_str(String*) return 0; } +bool Item_type_holder::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + DBUG_ASSERT(0); // should never be called + return true; +} + void Item_result_field::cleanup() { DBUG_ENTER("Item_result_field::cleanup()"); @@ -10557,11 +10623,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 c14a9499624..7572b7cece2 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 @@ -87,7 +87,11 @@ public: }; +#ifdef DBUG_OFF +static inline const char *dbug_print_item(Item *item) { return NULL; } +#else const char *dbug_print_item(Item *item); +#endif class Virtual_tmp_table; class sp_head; @@ -583,7 +587,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, @@ -687,6 +691,12 @@ protected: DBUG_ASSERT(fixed == 1); return (null_value= item->get_date_with_conversion(ltime, fuzzydate)); } + /* + This method is used if the item was not null but convertion to + TIME/DATE/DATETIME failed. We return a zero date if allowed, + otherwise - null. + */ + bool make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate); public: /* @@ -1369,7 +1379,12 @@ public: void split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, List<Item> &fields, Item **ref, uint flags); - virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)= 0; + bool get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool get_date_from_year(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_time(MYSQL_TIME *ltime) { return get_date(ltime, TIME_TIME_ONLY | TIME_INVALID_DATES); } // Get date with automatic TIME->DATETIME conversion @@ -1660,6 +1675,7 @@ public: */ virtual bool check_partition_func_processor(void *arg) { return 1;} virtual bool vcol_in_partition_func_processor(void *arg) { return 0; } + virtual bool rename_fields_processor(void *arg) { return 0; } /** Processor used to check acceptability of an item in the defining expression for a virtual column @@ -1673,6 +1689,12 @@ public: uint errors; /* Bits of possible errors */ const char *name; /* Not supported function */ }; + struct func_processor_rename + { + LEX_CSTRING db_name; + LEX_CSTRING table_name; + List<Create_field> fields; + }; virtual bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE); @@ -2324,6 +2346,7 @@ public: longlong val_int(); String *val_str(String *sp); my_decimal *val_decimal(my_decimal *decimal_value); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); bool is_null(); public: @@ -2586,6 +2609,7 @@ public: longlong val_int(); String *val_str(String *sp); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); bool is_null(); virtual void print(String *str, enum_query_type query_type); @@ -2622,6 +2646,10 @@ public: Item_num(THD *thd): Item_basic_constant(thd) { collation.set_numeric(); } Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); bool check_partition_func_processor(void *int_arg) { return FALSE;} + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } }; #define NO_CACHED_FIELD_INDEX ((uint)(-1)) @@ -2743,6 +2771,10 @@ public: longlong val_int() { return field->val_int(); } String *val_str(String *str) { return field->val_str(str); } my_decimal *val_decimal(my_decimal *dec) { return field->val_decimal(dec); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return field->get_date(ltime, fuzzydate); + } void make_field(THD *thd, Send_field *tmp_field); const Type_handler *type_handler() const { @@ -2898,6 +2930,7 @@ public: bool update_table_bitmaps_processor(void *arg); bool switch_to_nullable_fields_processor(void *arg); bool update_vcol_processor(void *arg); + bool rename_fields_processor(void *arg); bool check_vcol_func_processor(void *arg) { context= 0; @@ -3047,6 +3080,7 @@ public: longlong val_int(); String *val_str(String *str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); int save_in_field(Field *field, bool no_conversions); int save_safe_in_field(Field *field); bool send(Protocol *protocol, st_value *buffer); @@ -3765,6 +3799,10 @@ public: return (String*) &str_value; } my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_string(ltime, fuzzydate); + } int save_in_field(Field *field, bool no_conversions); const Type_handler *type_handler() const { return &type_handler_varchar; } bool basic_const_item() const { return 1; } @@ -4052,6 +4090,10 @@ public: str_value.bin_eq(&((Item_hex_constant*)item)->str_value); } String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } }; @@ -5397,6 +5439,8 @@ public: my_decimal *val_decimal(my_decimal *); double val_real(); longlong val_int(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_string(ltime, fuzzydate); } void copy(); int save_in_field(Field *field, bool no_conversions); Item *get_copy(THD *thd) @@ -5422,6 +5466,8 @@ public: { return null_value ? 0 : cached_value; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_int(ltime, fuzzydate); } virtual void copy(); Item *get_copy(THD *thd) { return get_item_copy<Item_copy_int>(thd, this); } @@ -5464,6 +5510,10 @@ public: { return (longlong) rint(val_real()); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_real(ltime, fuzzydate); + } void copy() { cached_value= item->val_real(); @@ -5489,6 +5539,10 @@ public: } double val_real(); longlong val_int(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_decimal(ltime, fuzzydate); + } void copy(); Item *get_copy(THD *thd) { return get_item_copy<Item_copy_decimal>(thd, this); } @@ -5983,6 +6037,8 @@ public: longlong val_int(); String* val_str(String *str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_int(ltime, fuzzydate); } bool cache_value(); int save_in_field(Field *field, bool no_conversions); Item *convert_to_basic_const_item(THD *thd); @@ -5991,6 +6047,15 @@ public: }; +class Item_cache_year: public Item_cache_int +{ +public: + Item_cache_year(THD *thd): Item_cache_int(thd, &type_handler_year) { } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_year(ltime, fuzzydate); } +}; + + class Item_cache_temporal: public Item_cache_int { protected: @@ -6058,6 +6123,8 @@ public: longlong val_int(); String* val_str(String *str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_real(ltime, fuzzydate); } bool cache_value(); Item *convert_to_basic_const_item(THD *thd); Item *get_copy(THD *thd) @@ -6076,6 +6143,8 @@ public: longlong val_int(); String* val_str(String *str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_decimal(ltime, fuzzydate); } bool cache_value(); Item *convert_to_basic_const_item(THD *thd); Item *get_copy(THD *thd) @@ -6102,6 +6171,8 @@ public: longlong val_int(); String* val_str(String *); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_string(ltime, fuzzydate); } CHARSET_INFO *charset() const { return value->charset(); }; int save_in_field(Field *field, bool no_conversions); bool cache_value(); @@ -6182,6 +6253,11 @@ public: illegal_method_call((const char*)"val_decimal"); return 0; }; + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + illegal_method_call((const char*)"val_decimal"); + return true; + } uint cols() const { return item_count; } Item *element_index(uint i) { return values[i]; } @@ -6282,6 +6358,7 @@ public: longlong val_int(); my_decimal *val_decimal(my_decimal *); String *val_str(String*); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); Field *create_tmp_field(bool group, TABLE *table) { return Item_type_holder::real_type_handler()-> diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 26c021f96b5..4296b2c6468 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1226,6 +1226,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); @@ -1249,6 +1250,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"); @@ -1422,6 +1450,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); @@ -1446,6 +1475,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()) { @@ -1683,6 +1713,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); @@ -1734,6 +1765,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); } @@ -1741,6 +1773,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(); } @@ -2683,7 +2716,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, @@ -2701,10 +2736,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 9392b51e69b..44d1063fd57 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -378,6 +378,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) { return get_item_copy<Item_in_optimizer>(thd, this); } }; @@ -2486,9 +2488,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 3796beebc13..f2dabf74060 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -704,6 +704,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; @@ -720,6 +721,7 @@ void Item_udf_func::fix_num_length_and_dec() max_length= float_length(NOT_FIXED_DEC); } } +#endif void Item_func::signal_divide_by_null() @@ -2703,7 +2705,7 @@ bool Item_func_min_max::get_date_native(MYSQL_TIME *ltime, ulonglong fuzzy_date) for (uint i=0; i < arg_count ; i++) { - longlong res= args[i]->val_temporal_packed(Item_func_min_max::field_type()); + longlong res= args[i]->val_datetime_packed(); /* Check if we need to stop (because of error or KILL) and stop the loop */ if (args[i]->null_value) @@ -2719,15 +2721,6 @@ bool Item_func_min_max::get_date_native(MYSQL_TIME *ltime, ulonglong fuzzy_date) ltime->time_type= MYSQL_TIMESTAMP_DATE; ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; } - else if (Item_func_min_max::field_type() == MYSQL_TYPE_TIME) - { - ltime->time_type= MYSQL_TIMESTAMP_TIME; - ltime->hour+= (ltime->month * 32 + ltime->day) * 24; - ltime->year= ltime->month= ltime->day= 0; - if (adjust_time_range_with_warn(ltime, - MY_MIN(decimals, TIME_SECOND_PART_DIGITS))) - return (null_value= true); - } if (!(fuzzy_date & TIME_TIME_ONLY) && ((null_value= check_date_with_warn(ltime, fuzzy_date, @@ -2738,6 +2731,29 @@ bool Item_func_min_max::get_date_native(MYSQL_TIME *ltime, ulonglong fuzzy_date) } +bool Item_func_min_max::get_time_native(MYSQL_TIME *ltime) +{ + DBUG_ASSERT(fixed == 1); + + Time value(args[0]); + if (!value.is_valid_time()) + return (null_value= true); + + for (uint i= 1; i < arg_count ; i++) + { + Time tmp(args[i]); + if (!tmp.is_valid_time()) + return (null_value= true); + + int cmp= value.cmp(&tmp); + if ((cmp_sign < 0 ? cmp : -cmp) < 0) + value= tmp; + } + value.copy_to_mysql_time(ltime); + return (null_value= 0); +} + + String *Item_func_min_max::val_str_native(String *str) { String *UNINIT_VAR(res); @@ -5538,6 +5554,13 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer) } +bool Item_user_var_as_out_param::get_date(MYSQL_TIME *ltime, ulonglong fuzzy) +{ + DBUG_ASSERT(0); + return true; +} + + void Item_user_var_as_out_param::print_for_load(THD *thd, String *str) { str->append('@'); @@ -6623,6 +6646,15 @@ my_decimal *Item_func_last_value::val_decimal(my_decimal *decimal_value) } +bool Item_func_last_value::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + evaluate_sideeffects(); + bool tmp= last_value->get_date(ltime, fuzzydate); + null_value= last_value->null_value; + return tmp; +} + + void Item_func_last_value::fix_length_and_dec() { last_value= args[arg_count -1]; diff --git a/sql/item_func.h b/sql/item_func.h index 536fe1bd5a7..b10223289b9 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -389,6 +389,8 @@ public: my_decimal *val_decimal(my_decimal *decimal_value); longlong val_int() { DBUG_ASSERT(fixed == 1); return (longlong) rint(val_real()); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_real(ltime, fuzzydate); } const Type_handler *type_handler() const { return &type_handler_double; } void fix_length_and_dec() { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); } @@ -758,6 +760,8 @@ public: { collation.set_numeric(); } double val_real(); String *val_str(String*str); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_int(ltime, fuzzydate); } const Type_handler *type_handler() const= 0; void fix_length_and_dec() {} }; @@ -951,6 +955,8 @@ public: double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal*); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_decimal(ltime, fuzzydate); } const Type_handler *type_handler() const { return &type_handler_newdecimal; } void fix_length_and_dec_generic() {} void fix_length_and_dec() @@ -1523,6 +1529,7 @@ public: longlong val_int_native(); my_decimal *val_decimal_native(my_decimal *); bool get_date_native(MYSQL_TIME *res, ulonglong fuzzydate); + bool get_time_native(MYSQL_TIME *res); double val_real() { @@ -1617,6 +1624,10 @@ public: longlong val_int() { return args[0]->val_int(); } String *val_str(String *str) { return args[0]->val_str(str); } my_decimal *val_decimal(my_decimal *dec) { return args[0]->val_decimal(dec); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return args[0]->get_date(ltime, fuzzydate); + } const char *func_name() const { return "rollup_const"; } bool const_item() const { return 0; } const Type_handler *type_handler() const { return args[0]->type_handler(); } @@ -2059,6 +2070,10 @@ public: { return mark_unsupported_function(func_name(), "()", arg, VCOL_NON_DETERMINISTIC); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } }; @@ -2356,6 +2371,8 @@ public: Field *create_field_for_create_select(TABLE *table) { return create_table_field_from_handler(table); } bool check_vcol_func_processor(void *arg); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return type_handler()->Item_get_date(this, ltime, fuzzydate); } }; @@ -2500,6 +2517,7 @@ public: double val_real(); longlong val_int(); String *val_str(String *str); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); my_decimal *val_decimal(my_decimal *decimal_buffer); /* fix_fields() binds variable name with its entry structure */ bool fix_fields(THD *thd, Item **ref); @@ -2547,6 +2565,10 @@ public: String* val_str(String*); my_decimal *val_decimal(my_decimal *dec_buf) { return val_decimal_from_real(dec_buf); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } /* TODO: fix to support views */ const char *func_name() const { return "get_system_var"; } /** @@ -2983,6 +3005,7 @@ public: longlong val_int(); String *val_str(String *); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); void fix_length_and_dec(); const char *func_name() const { return "last_value"; } const Type_handler *type_handler() const { return last_value->type_handler(); } diff --git a/sql/item_row.h b/sql/item_row.h index 064c1f267b4..064cb0782b1 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -82,6 +82,11 @@ public: illegal_method_call((const char*)"val_decimal"); return 0; }; + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + illegal_method_call((const char*)"get_date"); + return true; + } bool fix_fields(THD *thd, Item **ref); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void cleanup(); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index e342b6d5fb7..90d762c0191 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,99 +545,106 @@ 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); THD *thd= current_thd; - String *res,*use_as_buff; - uint i; - bool is_const= 0; + String *res; null_value=0; - if (!(res= arg_val_str(0, str, &is_const))) + if (!(res= args[0]->val_str(str))) goto null; - use_as_buff= &tmp_value; - for (i=1 ; i < arg_count ; i++) + + if (res != str) + str->copy(res->ptr(), res->length(), res->charset()); + + for (uint i= 1 ; i < arg_count ; i++) { - if (res->length() == 0) - { - /* - 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. - */ - if (!(res= arg_val_str(i, str, &is_const))) - goto null; - } - else - { - const String *res2; - if (!(res2=args[i]->val_str(use_as_buff))) - goto null; - if (res2->length() == 0) - continue; - if (!(res= append_value(thd, res, is_const, str, &use_as_buff, res2))) - goto null; - is_const= 0; - } + if (!(res= args[i]->val_str(&tmp_value)) || + append_value(thd, str, res)) + goto null; } - res->set_charset(collation.collation); - return res; + + str->set_charset(collation.collation); + return str; null: - null_value=1; + null_value= true; return 0; } String *Item_func_concat_operator_oracle::val_str(String *str) { - THD *thd= current_thd; DBUG_ASSERT(fixed == 1); - String *res, *use_as_buff; + THD *thd= current_thd; + String *res; uint i; - bool is_const= false; - null_value= 0; + null_value=0; // Search first non null argument for (i= 0; i < arg_count; i++) { - if ((res= arg_val_str(i, str, &is_const))) + if ((res= args[i]->val_str(str))) break; } if (i == arg_count) goto null; - use_as_buff= &tmp_value; + if (res != str) + str->copy(res->ptr(), res->length(), res->charset()); for (i++ ; i < arg_count ; i++) { - if (res->length() == 0) - { - // See comments in Item_func_concat::val_str() - String *tmp; - if (!(tmp= arg_val_str(i, str, &is_const))) - continue; - res= tmp; - } - else - { - const String *res2; - if (!(res2= args[i]->val_str(use_as_buff)) || res2->length() == 0) - continue; - if (!(res= append_value(thd, res, is_const, str, &use_as_buff, res2))) - goto null; - is_const= 0; - } + if (!(res= args[i]->val_str(&tmp_value)) || res->length() == 0) + continue; + if (append_value(thd, str, res)) + goto null; } - res->set_charset(collation.collation); - return res; + + str->set_charset(collation.collation); + return str; null: null_value= true; @@ -645,115 +652,21 @@ null: } -String *Item_func_concat::append_value(THD *thd, - String *res, - bool res_is_const, - String *str, - String **use_as_buff, - const String *res2) +bool Item_func_concat::append_value(THD *thd, String *res, const String *app) { - DBUG_ASSERT(res2->length() > 0); - - if ((ulong) res->length() + (ulong) res2->length() > + uint concat_len; + if ((concat_len= res->length() + app->length()) > thd->variables.max_allowed_packet) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_WARN_ALLOWED_PACKET_OVERFLOWED, - ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED), - func_name(), + ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(), thd->variables.max_allowed_packet); - return NULL; + return true; } - - uint32 concat_len= res->length() + res2->length(); - - if (!res_is_const && res->alloced_length() >= concat_len) - { // Use old buffer - return res->append(*res2) ? NULL : res; - } - - if (str->alloced_length() >= concat_len) - { - if (str->ptr() == res2->ptr()) - { - if (str->replace(0, 0, *res)) - return NULL; - } - else - { - if (str->copy(*res) || str->append(*res2)) - return NULL; - } - *use_as_buff= &tmp_value; - return str; - } - - if (res == &tmp_value) - { - if (res->append(*res2)) // Must be a blob - return NULL; - return res; - } - - if (res2 == &tmp_value) - { // This can happend only 1 time - if (tmp_value.replace(0, 0, *res)) - return NULL; - *use_as_buff= str; // Put next arg here - return &tmp_value; - } - - 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)) - return NULL; - *use_as_buff= str; // Put next arg here - return &tmp_value; - } - - /* - 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. - */ - - if (tmp_value.alloced_length() < concat_len) - { - if (tmp_value.alloced_length() == 0) - { - if (tmp_value.alloc(concat_len)) - return NULL; - } - else - { - uint32 new_len= tmp_value.alloced_length() > INT_MAX32 ? - UINT_MAX32 - 1 : - tmp_value.alloced_length() * 2; - set_if_bigger(new_len, concat_len); - if (tmp_value.realloc(new_len)) - return NULL; - } - } - - if (tmp_value.copy(*res) || tmp_value.append(*res2)) - return NULL; - - *use_as_buff= str; - return &tmp_value; + DBUG_ASSERT(!res->uses_buffer_owned_by(app)); + DBUG_ASSERT(!app->uses_buffer_owned_by(res)); + return realloc_result(res, concat_len) || res->append(*app); } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index faad324403a..08601b9d9d4 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -62,6 +62,8 @@ public: longlong val_int(); double val_real(); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_string(ltime, fuzzydate); } const Type_handler *type_handler() const { return string_type_handler(); } void left_right_max_length(); bool fix_fields(THD *thd, Item **ref); @@ -244,37 +246,14 @@ class Item_func_concat :public Item_str_func protected: String tmp_value; /* - Get the i-th argument val_str() and its const_item() - @param i[IN] - The argument number - @param str[IN] - The buffer for val_str() - @param is_const[IN/OUT] - If args[i]->val_str() returned a non-null value, - then args[i]->const_item() is returned here. - Otherwise, the value of is_const is not touched. - @retval - the result of val_str(). - */ - String *arg_val_str(uint i, String *str, bool *is_const) - { - String *res= args[i]->val_str(str); - if (res) - *is_const= args[i]->const_item(); - return res; - } - /* Append a non-NULL value to the result. @param [IN] thd - The current thread. @param [IN/OUT] res - The current val_str() return value. - @param [IN] res_is_const - If "false", then OK to append to "res" - @param [IN/OUT] str - The val_str() argument. - @param [IN] res2 - The value to be appended. - @param [IN/OUT] use_as_buff - Which buffer to use for the next argument: - args[next_arg]->val_str(use_as_buff) + @param [IN] app - The value to be appended. + @retval - false on success, true on error */ - String *append_value(THD *thd, - String *res, - bool res_is_const, - String *str, - String **use_as_buff, - const String *res2); + bool append_value(THD *thd, String *res, const String *app); + 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 bcc75131d02..a8051ccd469 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -2133,7 +2133,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) { @@ -5499,7 +5502,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 55c9d759ddf..dfe3287615b 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -401,6 +401,8 @@ public: String *val_str(String*); my_decimal *val_decimal(my_decimal *); bool val_bool(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_int(ltime, fuzzydate); } bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); void print(String *str, enum_query_type query_type); diff --git a/sql/item_sum.h b/sql/item_sum.h index cbf245f3cd3..1ed3d870bcc 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -734,6 +734,10 @@ public: longlong val_int() { return val_int_from_real(); /* Real as default */ } String *val_str(String*str); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } void reset_field(); }; @@ -1343,6 +1347,10 @@ public: void update_field(){DBUG_ASSERT(0);} void clear(); void cleanup(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return execute() || sp_result_field->get_date(ltime, fuzzydate); + } inline Field *get_sp_result_field() { return sp_result_field; @@ -1374,6 +1382,10 @@ public: { return mark_unsupported_function(name.str, arg, VCOL_IMPOSSIBLE); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } }; @@ -1523,6 +1535,10 @@ public: void update_field() {}; void cleanup(); virtual void print(String *str, enum_query_type query_type); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } }; @@ -1819,6 +1835,10 @@ public: { return val_decimal_from_string(decimal_value); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_string(ltime, fuzzydate); + } String* val_str(String* str); Item *copy_or_same(THD* thd); void no_rows_in_result() {} diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 744cdb388b0..761f619def8 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -181,6 +181,10 @@ public: str->set(nr, collation.collation); return str; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_int(ltime, fuzzydate); + } const char *func_name() const { return "month"; } const Type_handler *type_handler() const { return &type_handler_long; } void fix_length_and_dec() @@ -441,6 +445,10 @@ public: { return (odbc_type ? "dayofweek" : "weekday"); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } const Type_handler *type_handler() const { return &type_handler_long; } void fix_length_and_dec() { diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index cd0fb5058a6..85ca8b0624e 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -440,6 +440,17 @@ Item_sum_hybrid_simple::val_str(String *str) return retval; } +bool Item_sum_hybrid_simple::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + DBUG_ASSERT(fixed == 1); + if (null_value) + return 0; + bool retval= value->get_date(ltime, fuzzydate); + if ((null_value= value->null_value)) + DBUG_ASSERT(retval == true); + return retval; +} + Field *Item_sum_hybrid_simple::create_tmp_field(bool group, TABLE *table) { DBUG_ASSERT(0); @@ -536,5 +547,10 @@ void Item_window_func::print(String *str, enum_query_type query_type) { window_func()->print(str, query_type); str->append(" over "); +#ifndef DBUG_OFF + if (!window_spec) // one can call dbug_print_item() anytime in gdb + str->append(window_name); + else +#endif window_spec->print(str, query_type); } diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index 0a0a02c86b1..cb85a2c06d1 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -319,6 +319,7 @@ class Item_sum_hybrid_simple : public Item_sum, my_decimal *val_decimal(my_decimal *); void reset_field(); String *val_str(String *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); const Type_handler *type_handler() const { return Type_handler_hybrid_field_type::type_handler(); } void update_field(); @@ -1265,6 +1266,29 @@ public: return res; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + bool res; + if (force_return_blank) + { + null_value= true; + res= true; + } + else if (read_value_from_result_field) + { + if ((null_value= result_field->is_null())) + res= true; + else + res= result_field->get_date(ltime, fuzzydate); + } + else + { + res= window_func()->get_date(ltime, fuzzydate); + null_value= window_func()->null_value; + } + return res; + } + void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List<Item> &fields, uint flags); diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 83a25b7865c..5156bd08ef2 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -2734,7 +2734,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; @@ -2762,7 +2762,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 425b2b8ec1c..33e85ba5628 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 93500633d08..5c1afb1f82d 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 113d6f352ea..ac610f978fc 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5321,8 +5321,12 @@ bool test_if_equal_repl_errors(int expected_error, int actual_error) 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/mf_iocache_encr.cc b/sql/mf_iocache_encr.cc index 8d7cea4b050..9724ca4e19e 100644 --- a/sql/mf_iocache_encr.cc +++ b/sql/mf_iocache_encr.cc @@ -145,9 +145,10 @@ static int my_b_encr_write(IO_CACHE *info, const uchar *Buffer, size_t Count) if (info->seek_not_done) { - DBUG_ASSERT(info->pos_in_file == 0); + DBUG_ASSERT(info->pos_in_file % info->buffer_length == 0); + my_off_t wpos= info->pos_in_file / info->buffer_length * crypt_data->block_length; - if ((mysql_file_seek(info->file, 0, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR)) + if ((mysql_file_seek(info->file, wpos, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR)) { info->error= -1; DBUG_RETURN(1); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1b76483c7eb..1dff9c4591e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -560,7 +560,7 @@ ulong max_prepared_stmt_count; statements. */ ulong prepared_stmt_count=0; -my_thread_id global_thread_id= 1; +my_thread_id global_thread_id= 0; ulong current_pid; ulong slow_launch_threads = 0; uint sync_binlog_period= 0, sync_relaylog_period= 0, @@ -767,6 +767,9 @@ mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats, /* This protects against changes in master_info_index */ mysql_mutex_t LOCK_active_mi; +/* This protects connection id.*/ +mysql_mutex_t LOCK_thread_id; + /** The below lock protects access to two global server variables: max_prepared_stmt_count and prepared_stmt_count. These variables @@ -935,6 +938,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list, key_PARTITION_LOCK_auto_inc; PSI_mutex_key key_RELAYLOG_LOCK_index; PSI_mutex_key key_LOCK_relaylog_end_pos; +PSI_mutex_key key_LOCK_thread_id; PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state, key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry; PSI_mutex_key key_LOCK_binlog; @@ -978,6 +982,7 @@ static PSI_mutex_info all_server_mutexes[]= { &key_hash_filo_lock, "hash_filo::lock", 0}, { &key_LOCK_active_mi, "LOCK_active_mi", PSI_FLAG_GLOBAL}, { &key_LOCK_connection_count, "LOCK_connection_count", PSI_FLAG_GLOBAL}, + { &key_LOCK_thread_id, "LOCK_thread_id", PSI_FLAG_GLOBAL}, { &key_LOCK_crypt, "LOCK_crypt", PSI_FLAG_GLOBAL}, { &key_LOCK_delayed_create, "LOCK_delayed_create", PSI_FLAG_GLOBAL}, { &key_LOCK_delayed_insert, "LOCK_delayed_insert", PSI_FLAG_GLOBAL}, @@ -2071,8 +2076,8 @@ pthread_handler_t kill_server_thread(void *arg __attribute__((unused))) extern "C" sig_handler print_signal_warning(int sig) { if (global_system_variables.log_warnings) - sql_print_warning("Got signal %d from thread %ld", sig, - (ulong) my_thread_id()); + sql_print_warning("Got signal %d from thread %u", sig, + (uint)my_thread_id()); #ifdef SIGNAL_HANDLER_RESET_ON_DELIVERY my_sigset(sig,print_signal_warning); /* int. thread system calls */ #endif @@ -2365,6 +2370,7 @@ static void clean_up_mutexes() mysql_mutex_destroy(&LOCK_crypt); mysql_mutex_destroy(&LOCK_user_conn); mysql_mutex_destroy(&LOCK_connection_count); + mysql_mutex_destroy(&LOCK_thread_id); mysql_mutex_destroy(&LOCK_stats); mysql_mutex_destroy(&LOCK_global_user_client_stats); mysql_mutex_destroy(&LOCK_global_table_stats); @@ -4257,7 +4263,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); } @@ -4752,6 +4758,8 @@ static int init_thread_environment() &LOCK_short_uuid_generator, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_connection_count, &LOCK_connection_count, MY_MUTEX_INIT_FAST); + mysql_mutex_init(key_LOCK_thread_id, + &LOCK_thread_id, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_stats, &LOCK_stats, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_global_user_client_stats, &LOCK_global_user_client_stats, MY_MUTEX_INIT_FAST); @@ -8906,7 +8914,7 @@ static int mysql_init_variables(void) denied_connections= 0; executed_events= 0; global_query_id= 1; - global_thread_id= 1; + global_thread_id= 0; strnmov(server_version, MYSQL_SERVER_VERSION, sizeof(server_version)-1); threads.empty(); thread_cache.empty(); @@ -10592,3 +10600,96 @@ void init_server_psi_keys(void) } #endif /* HAVE_PSI_INTERFACE */ + + +/* + Connection ID allocation. + + We need to maintain thread_ids in the 32bit range, + because this is how it is passed to the client in the protocol. + + The idea is to maintain a id range, initially set to + (0,UINT32_MAX). Whenever new id is needed, we increment the + lower limit and return its new value. + + On "overflow", if id can not be generated anymore(i.e lower == upper -1), + we recalculate the range boundaries. + To do that, we first collect thread ids that are in use, by traversing + THD list, and find largest region within (0,UINT32_MAX), that is still free. + +*/ + +static my_thread_id thread_id_max= UINT_MAX32; + +#include <vector> +#include <algorithm> + +/* + Find largest unused thread_id range. + + i.e for every number N within the returned range, + there is no existing connection with thread_id equal to N. + + The range is exclusive, lower bound is always >=0 and + upper bound <=MAX_UINT32. + + @param[out] low - lower bound for the range + @param[out] high - upper bound for the range +*/ +static void recalculate_thread_id_range(my_thread_id *low, my_thread_id *high) +{ + std::vector<my_thread_id> ids; + + // Add sentinels + ids.push_back(0); + ids.push_back(UINT_MAX32); + + mysql_mutex_lock(&LOCK_thread_count); + + I_List_iterator<THD> it(threads); + THD *thd; + while ((thd=it++)) + ids.push_back(thd->thread_id); + + mysql_mutex_unlock(&LOCK_thread_count); + + std::sort(ids.begin(), ids.end()); + my_thread_id max_gap= 0; + for (size_t i= 0; i < ids.size() - 1; i++) + { + my_thread_id gap= ids[i+1] - ids[i]; + if (gap > max_gap) + { + *low= ids[i]; + *high= ids[i+1]; + max_gap= gap; + } + } + + if (max_gap < 2) + { + /* Can't find free id. This is not really possible, + we'd need 2^32 connections for this to happen.*/ + sql_print_error("Cannot find free connection id."); + abort(); + } +} + + +my_thread_id next_thread_id(void) +{ + my_thread_id retval; + DBUG_EXECUTE_IF("thread_id_overflow", global_thread_id= thread_id_max-2;); + + mysql_mutex_lock(&LOCK_thread_id); + + if (unlikely(global_thread_id == thread_id_max - 1)) + { + recalculate_thread_id_range(&global_thread_id, &thread_id_max); + } + + retval= ++global_thread_id; + + mysql_mutex_unlock(&LOCK_thread_id); + return retval; +} diff --git a/sql/mysqld.h b/sql/mysqld.h index bb22753bbf1..069ad85dd16 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -772,15 +772,7 @@ inline query_id_t get_query_id() } /* increment global_thread_id and return it. */ -inline __attribute__((warn_unused_result)) my_thread_id next_thread_id() -{ - return my_atomic_add64_explicit((int64*) &global_thread_id, 1, MY_MEMORY_ORDER_RELAXED); -} - -#if defined(MYSQL_DYNAMIC_PLUGIN) && defined(_WIN32) -extern "C" my_thread_id next_thread_id_noinline(); -#define next_thread_id() next_thread_id_noinline() -#endif +extern __attribute__((warn_unused_result)) my_thread_id next_thread_id(void); /* TODO: Replace this with an inline function. diff --git a/sql/net_serv.cc b/sql/net_serv.cc index cab9b0ede69..4c3771bc710 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 @@ -53,6 +53,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 @@ -68,6 +69,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 @@ -1160,7 +1164,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 e783ee9bff4..77bf64f991a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2075,7 +2075,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/procedure.h b/sql/procedure.h index fdbfab7f17c..1c24901791c 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -59,6 +59,10 @@ public: DBUG_ASSERT(0); // impossible return mark_unsupported_function("proc", arg, VCOL_IMPOSSIBLE); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } Item* get_copy(THD *thd) { return 0; } }; diff --git a/sql/sp.cc b/sql/sp.cc index 5921440057e..773a5479199 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -828,7 +828,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 b405dadb9fe..cdb5e256e46 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -521,7 +521,7 @@ sp_head::sp_head(const Sp_handler *sph) m_defstr(null_clex_str), m_sp_cache_version(0), m_creation_ctx(0), - unsafe_flags(0), m_select_number(1), + unsafe_flags(0), m_created(0), m_modified(0), m_recursion_level(0), @@ -669,7 +669,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); @@ -970,12 +970,13 @@ 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; const uint status_backup_mask= SERVER_STATUS_CURSOR_EXISTS | SERVER_STATUS_LAST_ROW_SENT; + MEM_ROOT *user_var_events_alloc_saved= 0; Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer; Object_creation_ctx *UNINIT_VAR(saved_creation_ctx); Diagnostics_area *da= thd->get_stmt_da(); @@ -985,19 +986,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, "per_instruction_memroot", MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); @@ -1087,6 +1075,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. @@ -1168,9 +1157,11 @@ sp_head::execute(THD *thd, bool merge_da_on_success) Will write this SP statement into binlog separately. TODO: consider changing the condition to "not inside event union". */ - MEM_ROOT *user_var_events_alloc_saved= thd->user_var_events_alloc; if (thd->locked_tables_mode <= LTM_LOCK_TABLES) + { + user_var_events_alloc_saved= thd->user_var_events_alloc; thd->user_var_events_alloc= thd->mem_root; + } sql_digest_state *parent_digest= thd->m_digest; thd->m_digest= NULL; @@ -1240,6 +1231,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; @@ -1345,16 +1337,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); } @@ -3037,7 +3019,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 23717513af9..7f041058829 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -243,7 +243,6 @@ private: */ uint32 unsafe_flags; - uint m_select_number; public: inline Stored_program_creation_ctx *get_creation_ctx() { @@ -831,8 +830,6 @@ public: sp_pcontext *get_parse_context() { return m_pcont; } - void set_select_number(uint num) { m_select_number= num; } - bool check_execute_access(THD *thd) const; private: diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 68d6ad6b0b8..b1faed6aa36 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -5834,8 +5834,8 @@ static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname, (that should be merged) are sorted together. The grantee's ACL_DB element is not necessarily the first and may be not present at all. */ - ACL_DB **first= NULL, *UNINIT_VAR(merged); - ulong UNINIT_VAR(access), update_flags= 0; + ACL_DB **first= NULL, *merged= NULL; + ulong access= 0, update_flags= 0; for (ACL_DB **cur= dbs.front(); cur <= dbs.back(); cur++) { if (!first || (!dbname && strcmp(cur[0]->db, cur[-1]->db))) @@ -6040,8 +6040,8 @@ static bool merge_role_table_and_column_privileges(ACL_ROLE *grantee, } grants.sort(table_name_sort); - GRANT_TABLE **first= NULL, *UNINIT_VAR(merged), **cur; - ulong UNINIT_VAR(privs), UNINIT_VAR(cols), update_flags= 0; + GRANT_TABLE **first= NULL, *merged= NULL, **cur; + ulong privs= 0, cols= 0, update_flags= 0; for (cur= grants.front(); cur <= grants.back(); cur++) { if (!first || @@ -6164,8 +6164,8 @@ static bool merge_role_routine_grant_privileges(ACL_ROLE *grantee, } grants.sort(routine_name_sort); - GRANT_NAME **first= NULL, *UNINIT_VAR(merged); - ulong UNINIT_VAR(privs); + GRANT_NAME **first= NULL, *merged= NULL; + ulong privs= 0 ; for (GRANT_NAME **cur= grants.front(); cur <= grants.back(); cur++) { if (!first || diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 6c56e4c1010..4cff69060d1 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -703,8 +703,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. */ @@ -1042,7 +1041,7 @@ send_result_message: if (!thd->open_temporary_tables(table) && (table->table= open_ltable(thd, table, lock_type, 0))) { - uint save_flags; + ulonglong save_flags; /* Store the original value of alter_info->flags */ save_flags= alter_info->flags; diff --git a/sql/sql_alloc.h b/sql/sql_alloc.h index 43f46160122..e7cda5b2abf 100644 --- a/sql/sql_alloc.h +++ b/sql/sql_alloc.h @@ -1,7 +1,7 @@ #ifndef SQL_ALLOC_INCLUDED #define SQL_ALLOC_INCLUDED /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2017, MariaDB AB + Copyright (c) 2017, 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 @@ -39,11 +39,11 @@ 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 *, MEM_ROOT *){} 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_alter.h b/sql/sql_alter.h index 524cff62a12..c7cc98aacc4 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -1,5 +1,5 @@ /* Copyright (c) 2010, 2014, Oracle and/or its affiliates. - Copyright (c) 2013, 2014, Monty Program Ab. + Copyright (c) 2013, 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 @@ -38,68 +38,66 @@ public: type of index to be added/dropped. */ - enum operations_used_flags - { - // Set for ADD [COLUMN] - ALTER_ADD_COLUMN = 1L << 0, - // Set for DROP [COLUMN] - ALTER_DROP_COLUMN = 1L << 1, - // Set for CHANGE [COLUMN] | MODIFY [CHANGE] & mysql_recreate_table - ALTER_CHANGE_COLUMN = 1L << 2, - // Set for ADD INDEX | ADD KEY | ADD PRIMARY KEY | ADD UNIQUE KEY | - // ADD UNIQUE INDEX | ALTER ADD [COLUMN] - ALTER_ADD_INDEX = 1L << 3, - // Set for DROP PRIMARY KEY | DROP FOREIGN KEY | DROP KEY | DROP INDEX - ALTER_DROP_INDEX = 1L << 4, - // Set for RENAME [TO] - ALTER_RENAME = 1L << 5, - // Set for ORDER BY - ALTER_ORDER = 1L << 6, - // Set for table_options - ALTER_OPTIONS = 1L << 7, - // Set for ALTER [COLUMN] ... SET DEFAULT ... | DROP DEFAULT - ALTER_CHANGE_COLUMN_DEFAULT = 1L << 8, - // Set for DISABLE KEYS | ENABLE KEYS - ALTER_KEYS_ONOFF = 1L << 9, - // Set for FORCE, ENGINE(same engine), by mysql_recreate_table() - ALTER_RECREATE = 1L << 10, - // Set for ADD PARTITION - ALTER_ADD_PARTITION = 1L << 11, - // Set for DROP PARTITION - ALTER_DROP_PARTITION = 1L << 12, - // Set for COALESCE PARTITION - ALTER_COALESCE_PARTITION = 1L << 13, - // Set for REORGANIZE PARTITION ... INTO - ALTER_REORGANIZE_PARTITION = 1L << 14, - // Set for partition_options - ALTER_PARTITION = 1L << 15, - // Set for LOAD INDEX INTO CACHE ... PARTITION - // Set for CACHE INDEX ... PARTITION - ALTER_ADMIN_PARTITION = 1L << 16, - // Set for REORGANIZE PARTITION - ALTER_TABLE_REORG = 1L << 17, - // Set for REBUILD PARTITION - ALTER_REBUILD_PARTITION = 1L << 18, - // Set for partitioning operations specifying ALL keyword - ALTER_ALL_PARTITION = 1L << 19, - // Set for REMOVE PARTITIONING - ALTER_REMOVE_PARTITIONING = 1L << 20, - // Set for ADD FOREIGN KEY - ADD_FOREIGN_KEY = 1L << 21, - // Set for DROP FOREIGN KEY - DROP_FOREIGN_KEY = 1L << 22, - // Set for EXCHANGE PARITION - ALTER_EXCHANGE_PARTITION = 1L << 23, - // Set by Sql_cmd_alter_table_truncate_partition::execute() - ALTER_TRUNCATE_PARTITION = 1L << 24, - // Set for ADD [COLUMN] FIRST | AFTER - ALTER_COLUMN_ORDER = 1L << 25, - ALTER_ADD_CHECK_CONSTRAINT = 1L << 27, - ALTER_DROP_CHECK_CONSTRAINT = 1L << 28, - ALTER_COLUMN_UNVERSIONED = 1L << 29, - ALTER_ADD_SYSTEM_VERSIONING = 1L << 30, - ALTER_DROP_SYSTEM_VERSIONING= 1L << 31, - }; + /** Set for ADD [COLUMN] */ + static const ulonglong ALTER_ADD_COLUMN = 1ULL << 0; + /** Set for DROP [COLUMN] */ + static const ulonglong ALTER_DROP_COLUMN = 1ULL << 1; + /** Set for CHANGE [COLUMN] | MODIFY [CHANGE] & mysql_recreate_table */ + static const ulonglong ALTER_CHANGE_COLUMN = 1ULL << 2; + /** Set for ADD INDEX | ADD KEY | ADD PRIMARY KEY | ADD UNIQUE KEY | + ADD UNIQUE INDEX | ALTER ADD [COLUMN] */ + static const ulonglong ALTER_ADD_INDEX = 1ULL << 3; + /** Set for DROP PRIMARY KEY | DROP FOREIGN KEY | DROP KEY | DROP INDEX */ + static const ulonglong ALTER_DROP_INDEX = 1ULL << 4; + /** Set for RENAME [TO] */ + static const ulonglong ALTER_RENAME = 1ULL << 5; + /** Set for ORDER BY */ + static const ulonglong ALTER_ORDER = 1ULL << 6; + /** Set for table_options */ + static const ulonglong ALTER_OPTIONS = 1ULL << 7; + /** Set for ALTER [COLUMN] ... SET DEFAULT ... | DROP DEFAULT */ + static const ulonglong ALTER_CHANGE_COLUMN_DEFAULT = 1ULL << 8; + /** Set for DISABLE KEYS | ENABLE KEYS */ + static const ulonglong ALTER_KEYS_ONOFF = 1ULL << 9; + /** Set for FORCE, ENGINE(same engine), by mysql_recreate_table() */ + static const ulonglong ALTER_RECREATE = 1ULL << 10; + /** Set for ADD PARTITION */ + static const ulonglong ALTER_ADD_PARTITION = 1ULL << 11; + /** Set for DROP PARTITION */ + static const ulonglong ALTER_DROP_PARTITION = 1ULL << 12; + /** Set for COALESCE PARTITION */ + static const ulonglong ALTER_COALESCE_PARTITION = 1ULL << 13; + /** Set for REORGANIZE PARTITION ... INTO */ + static const ulonglong ALTER_REORGANIZE_PARTITION = 1ULL << 14; + /** Set for partition_options */ + static const ulonglong ALTER_PARTITION = 1ULL << 15; + /** Set for LOAD INDEX INTO CACHE ... PARTITION + and CACHE INDEX ... PARTITION */ + static const ulonglong ALTER_ADMIN_PARTITION = 1ULL << 16; + /** Set for REORGANIZE PARTITION */ + static const ulonglong ALTER_TABLE_REORG = 1ULL << 17; + /** Set for REBUILD PARTITION */ + static const ulonglong ALTER_REBUILD_PARTITION = 1ULL << 18; + /** Set for partitioning operations specifying ALL keyword */ + static const ulonglong ALTER_ALL_PARTITION = 1ULL << 19; + /** Set for REMOVE PARTITIONING */ + static const ulonglong ALTER_REMOVE_PARTITIONING = 1ULL << 20; + /** Set for ADD FOREIGN KEY */ + static const ulonglong ADD_FOREIGN_KEY = 1ULL << 21; + /** Set for DROP FOREIGN KEY */ + static const ulonglong DROP_FOREIGN_KEY = 1ULL << 22; + /** Set for EXCHANGE PARITION */ + static const ulonglong ALTER_EXCHANGE_PARTITION = 1ULL << 23; + /** Set by Sql_cmd_alter_table_truncate_partition::execute() */ + static const ulonglong ALTER_TRUNCATE_PARTITION = 1ULL << 24; + /** Set for ADD [COLUMN] FIRST | AFTER */ + static const ulonglong ALTER_COLUMN_ORDER = 1ULL << 25; + static const ulonglong ALTER_ADD_CHECK_CONSTRAINT = 1ULL << 27; + static const ulonglong ALTER_DROP_CHECK_CONSTRAINT = 1ULL << 28; + static const ulonglong ALTER_RENAME_COLUMN = 1ULL << 29; + static const ulonglong ALTER_COLUMN_UNVERSIONED = 1ULL << 30; + static const ulonglong ALTER_ADD_SYSTEM_VERSIONING = 1ULL << 31; + static const ulonglong ALTER_DROP_SYSTEM_VERSIONING= 1ULL << 32; enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; @@ -176,7 +174,7 @@ public: }; List<Virtual_column_info> check_constraint_list; // Type of ALTER TABLE operation. - uint flags; + ulonglong flags; // Enable or disable keys. enum_enable_or_disable keys_onoff; // List of partitions. diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c46a825f9d7..3e1d5ffd63a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8600,8 +8600,14 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) Item_func_match *ifm; while ((ifm=li++)) - if (ifm->init_search(thd, no_order)) - return 1; + 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 if (ifm->init_search(thd, no_order)) + return 1; } return 0; } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 968cd9970f5..c8f18556d50 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1187,7 +1187,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) @@ -1564,6 +1568,8 @@ def_week_frmt: %zu, 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); } @@ -2573,6 +2579,7 @@ void Query_cache::init() */ if (global_system_variables.query_cache_type == 0) { + m_cache_status= DISABLE_REQUEST; free_cache(); m_cache_status= DISABLED; } @@ -2781,13 +2788,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) @@ -2795,6 +2806,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 1e4be95bd2a..f10a5e51b59 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -784,6 +784,12 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock) init_sql_alloc(&main_mem_root, "THD::main_mem_root", ALLOC_ROOT_MIN_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC)); + /* + Allocation of user variables for binary logging is always done with main + mem root + */ + user_var_events_alloc= mem_root; + stmt_arena= this; thread_stack= 0; scheduler= thread_scheduler; // Will be fixed later @@ -2867,6 +2873,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++)) { @@ -2876,6 +2885,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; } @@ -2883,17 +2893,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; } @@ -3821,7 +3827,7 @@ void Statement::set_statement(Statement *stmt) { id= stmt->id; column_usage= stmt->column_usage; - 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 20bf2272db8..4722f3f5989 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1098,6 +1098,21 @@ public: LEX_CSTRING 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. @@ -1249,6 +1264,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); @@ -2967,7 +3005,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 @@ -3781,10 +3818,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 @@ -4645,7 +4686,7 @@ public: void set_local_lex(sp_lex_local *sublex) { DBUG_ASSERT(lex->sphead); - lex= sublex; + lex= stmt_lex= sublex; /* Reset part of parser state which needs this. */ m_parser_state->m_yacc.reset_before_substatement(); } diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index ea7ff138f10..05d12998026 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -830,7 +830,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; @@ -1017,6 +1017,10 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) and it was unsuccesful. Yet for units cloned from the spec it has not been done yet. */ + With_clause *attached_with_clause= sl->get_with_clause(); + if (attached_with_clause && + (found= attached_with_clause->find_table_def(table, NULL))) + break; master_unit= sl->master_unit(); outer_sl= master_unit->outer_select(); With_element *with_elem= sl->get_with_element(); @@ -1030,13 +1034,6 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) if (outer_sl && !outer_sl->get_with_element()) break; } - else - { - With_clause *attached_with_clause= sl->get_with_clause(); - if (attached_with_clause && - (found= attached_with_clause->find_table_def(table, NULL))) - break; - } /* Do not look for the table's definition beyond the scope of the view */ if (master_unit->is_view) break; @@ -1078,7 +1075,7 @@ bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem) if (!with_elem->is_referenced() || with_elem->is_recursive) { derived= with_elem->spec; - if (derived->get_master() != select_lex && + if (derived != select_lex->master_unit() && !is_with_table_recursive_reference()) { derived->move_as_slave(select_lex); @@ -1088,7 +1085,6 @@ bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem) { if(!(derived= with_elem->clone_parsed_spec(thd, this))) return true; - derived->with_element= with_elem; } derived->first_select()->linkage= DERIVED_TABLE_TYPE; with_elem->inc_references(); diff --git a/sql/sql_cte.h b/sql/sql_cte.h index 036f0335c10..13e9b83955c 100644 --- a/sql/sql_cte.h +++ b/sql/sql_cte.h @@ -158,7 +158,7 @@ public: query_name(name), column_list(list), spec(unit), is_recursive(false), with_anchor(false), level(0), rec_result(NULL) - {} + { unit->with_element= this; } bool check_dependencies_in_spec(); diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index b32571b2ed3..bb6bcd253f7 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -215,7 +215,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 12f230724fb..be5058b7c63 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) { @@ -384,7 +388,6 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) thd->save_prep_leaf_list= TRUE; arena= thd->activate_stmt_arena_if_needed(&backup); // For easier test - derived->merged= TRUE; if (!derived->merged_for_insert || (derived->is_multitable() && @@ -448,6 +451,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) if (parent_lex->join) parent_lex->join->table_count+= dt_select->join->table_count - 1; } + derived->merged= TRUE; if (derived->get_unit()->prepared) { Item *expr= derived->on_expr; @@ -744,6 +748,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_unit(thd))) @@ -885,6 +900,11 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) DBUG_PRINT("enter", ("Alias: '%s' Unit: %p", (derived->alias.str ? derived->alias.str : "<NULL>"), derived->get_unit())); + if (derived->merged) + { + DBUG_PRINT("info", ("Irreversibly merged: exit")); + DBUG_RETURN(FALSE); + } lex->current_select= first_select; diff --git a/sql/sql_explain.h b/sql/sql_explain.h index 7fb50a6cb04..38250cc40ce 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 linkage(UNSPECIFIED_TYPE), message(NULL), having(NULL), having_value(Item::COND_UNDEF), @@ -218,6 +221,9 @@ public: void add_linkage(Json_writer *writer); public: +#ifndef DBUG_OFF + SELECT_LEX *select_lex; +#endif const char *select_type; enum sub_select_type linkage; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 4cef25a9c29..84ec1513cf4 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 dadd419ade5..fb8660aa79d 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 0899082ca98..a2a9e5b2f16 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 @@ -675,6 +675,8 @@ void lex_start(THD *thd) void LEX::start(THD *thd_arg) { DBUG_ENTER("LEX::start"); + DBUG_PRINT("info", ("This: %p thd_arg->lex: %p thd_arg->stmt_lex: %p", + this, thd_arg->lex, thd_arg->stmt_lex)); thd= unit.thd= thd_arg; @@ -682,6 +684,7 @@ void LEX::start(THD *thd_arg) context_stack.empty(); unit.init_query(); + current_select_number= 1; select_lex.linkage= UNSPECIFIED_TYPE; /* 'parent_lex' is used in init_query() so it must be before it. */ select_lex.parent_lex= this; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 3505165196f..45fbe38e974 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 @@ -590,7 +590,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. @@ -845,7 +845,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. */ @@ -2705,7 +2711,10 @@ struct LEX: public Query_tables_list DYNAMIC_ARRAY plugins; plugin_ref plugins_static_buffer[INITIAL_LEX_PLUGIN_LIST_SIZE]; - uint number_of_selects; // valid only for view + /** SELECT of CREATE VIEW statement */ + LEX_STRING create_view_select; + + 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.cc b/sql/sql_list.cc index e938d5515c9..3512c7fc2ef 100644 --- a/sql/sql_list.cc +++ b/sql/sql_list.cc @@ -39,21 +39,21 @@ void free_list(I_List <i_string> *list) } -base_list::base_list(const base_list &rhs, MEM_ROOT *mem_root) +bool base_list::copy(const base_list *rhs, MEM_ROOT *mem_root) { - if (rhs.elements) + bool error= 0; + if (rhs->elements) { /* It's okay to allocate an array of nodes at once: we never call a destructor for list_node objects anyway. */ - first= (list_node*) alloc_root(mem_root, - sizeof(list_node) * rhs.elements); - if (first) + if ((first= (list_node*) alloc_root(mem_root, + sizeof(list_node) * rhs->elements))) { - elements= rhs.elements; + elements= rhs->elements; list_node *dst= first; - list_node *src= rhs.first; + list_node *src= rhs->first; for (; dst < first + elements - 1; dst++, src= src->next) { dst->info= src->info; @@ -64,10 +64,12 @@ base_list::base_list(const base_list &rhs, MEM_ROOT *mem_root) dst->next= &end_of_list; /* Setup 'last' member */ last= &dst->next; - return; + return 0; } + error= 1; } elements= 0; first= &end_of_list; last= &first; + return error; } diff --git a/sql/sql_list.h b/sql/sql_list.h index c708ed6d2f9..311e601490b 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -162,7 +162,8 @@ public: need to copy elements by value, you should employ list_copy_and_replace_each_value after creating a copy. */ - base_list(const base_list &rhs, MEM_ROOT *mem_root); + bool copy(const base_list *rhs, MEM_ROOT *mem_root); + base_list(const base_list &rhs, MEM_ROOT *mem_root) { copy(&rhs, mem_root); } inline base_list(bool error) { } inline bool push_back(void *info) { @@ -496,6 +497,8 @@ public: inline void disjoin(List<T> *list) { base_list::disjoin(list); } inline bool add_unique(T *a, bool (*eq)(T *a, T *b)) { return base_list::add_unique(a, (List_eq *)eq); } + inline bool copy(const List<T> *list, MEM_ROOT *root) + { return base_list::copy(list, root); } void delete_elements(void) { list_node *element,*next; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4c87dd27321..67181c6eb5e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7514,7 +7514,12 @@ void THD::reset_for_next_command(bool do_clear_error) clear_error(1); free_list= 0; - select_number= 1; + /* + We also assign stmt_lex in lex_start(), but during bootstrap this + code is executed first. + */ + stmt_lex= &main_lex; stmt_lex->current_select_number= 1; + DBUG_PRINT("info", ("Lex %p stmt_lex: %p", lex, stmt_lex)); /* Those two lines below are theoretically unneeded as THD::cleanup_after_query() should take care of this already. @@ -7564,10 +7569,8 @@ void THD::reset_for_next_command(bool do_clear_error) thread_specific_used= FALSE; if (opt_bin_log) - { reset_dynamic(&user_var_events); - user_var_events_alloc= mem_root; - } + DBUG_ASSERT(user_var_events_alloc == &main_mem_root); enable_slow_log= variables.sql_log_slow; get_stmt_da()->reset_for_next_command(); rand_used= 0; @@ -7634,7 +7637,7 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) { 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 b7ab9185033..5d1f5d4e1a3 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4566,8 +4566,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 */ @@ -4584,7 +4590,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, Alter_info::ALTER_REBUILD_PARTITION)) { partition_info *tab_part_info; - uint flags= 0; + ulonglong flags= 0; bool is_last_partition_reorged= FALSE; part_elem_value *tab_max_elem_val= NULL; part_elem_value *alt_max_elem_val= NULL; diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index d733e6c3684..605f96293d3 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -490,6 +490,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 83775f66a81..dbc03234c44 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; @@ -3796,9 +3782,9 @@ void Prepared_statement::cleanup_stmt() DBUG_ENTER("Prepared_statement::cleanup_stmt"); DBUG_PRINT("enter",("stmt: %p", this)); lex->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; } @@ -3881,6 +3867,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)) DBUG_RETURN(TRUE); @@ -3986,8 +3973,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); @@ -4124,7 +4109,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) { @@ -4267,7 +4251,6 @@ Prepared_statement::execute_bulk_loop(String *expanded_query, #ifdef DBUG_ASSERT_EXISTS 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 66d96dd62dc..a58c34cc2fa 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, 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 @@ -286,6 +286,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); @@ -337,7 +340,7 @@ bool dbug_user_var_equals_int(THD *thd, const char *name, int value) } return FALSE; } -#endif +#endif /** @@ -1105,6 +1108,9 @@ JOIN::prepare(TABLE_LIST *tables_init, join_list= &select_lex->top_join_list; union_part= unit_arg->is_unit_op(); + // simple check that we got usable conds + dbug_print_item(conds); + if (select_lex->handle_derived(thd->lex, DT_PREPARE)) DBUG_RETURN(-1); @@ -1224,9 +1230,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(); } @@ -3637,8 +3649,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) @@ -3783,6 +3798,17 @@ bool 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 && @@ -11109,7 +11135,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; @@ -12934,8 +12960,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 ) @@ -13339,7 +13365,7 @@ public: } static void operator delete(void *ptr __attribute__((unused)), size_t size __attribute__((unused))) - { TRASH(ptr, size); } + { TRASH_FREE(ptr, size); } static void operator delete(void *, MEM_ROOT*) {} @@ -16321,9 +16347,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)) && @@ -17560,7 +17587,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()); } } @@ -22863,7 +22890,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 @@ -22873,9 +22903,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; @@ -23012,6 +23044,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); @@ -23040,7 +23075,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= @@ -23049,7 +23084,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) @@ -23108,7 +23143,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) @@ -23439,6 +23474,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 @@ -25461,7 +25497,9 @@ int JOIN::save_explain_data_intern(Explain_query *output, Explain_select(output->mem_root, thd->lex->analyze_stmt))) DBUG_RETURN(1); - +#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 b4f84e696e0..f8911fbba01 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -2031,7 +2031,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, @@ -2112,7 +2112,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); } static void operator delete(void *, THD *) throw(){} Virtual_tmp_table(THD *thd) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index eb0c014f060..6d5c4adc521 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2698,7 +2698,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); } static void operator delete(void *, MEM_ROOT *){} my_thread_id thread_id; @@ -5434,7 +5434,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs); } - for (int i= 4; i < 20; i++) + for (uint i= 4; i < table->s->fields; i++) { if (i == 7 || (i > 12 && i < 17) || i == 18) continue; @@ -5612,8 +5612,15 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, { table->field[10]->store((longlong) file->stats.max_data_file_length, TRUE); + table->field[10]->set_notnull(); } table->field[11]->store((longlong) file->stats.index_file_length, TRUE); + if (file->stats.max_index_file_length) + { + table->field[21]->store((longlong) file->stats.max_index_file_length, + TRUE); + table->field[21]->set_notnull(); + } table->field[12]->store((longlong) file->stats.delete_length, TRUE); if (show_table->found_next_number_field) { @@ -5648,6 +5655,11 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, table->field[18]->set_notnull(); } } + /* If table is a temporary table */ + LEX_CSTRING tmp= { STRING_WITH_LEN("N") }; + if (show_table->s->tmp_table != NO_TMP_TABLE) + tmp.str= "Y"; + table->field[22]->store(tmp.str, tmp.length, cs); } err: @@ -8855,6 +8867,9 @@ ST_FIELD_INFO tables_fields_info[]= OPEN_FULL_TABLE}, {"TABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, "Comment", OPEN_FRM_ONLY}, + {"MAX_INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, + (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_index_length", OPEN_FULL_TABLE}, + {"TEMPORARY", 1, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, "Temporary", OPEN_FRM_ONLY}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} }; diff --git a/sql/sql_string.h b/sql/sql_string.h index 25940196fda..5cabcc02aae 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -3,7 +3,7 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2008, 2017, MariaDB Corporation. + Copyright (c) 2008, 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 @@ -184,11 +184,12 @@ public: { (void) ptr_arg; (void) size; - TRASH(ptr_arg, size); + TRASH_FREE(ptr_arg, size); } static void operator delete(void *, 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); } static void operator delete[](void *ptr, MEM_ROOT *mem_root) { /* never called */ } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b9c14bd34c3..1b066cd2df4 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6378,6 +6378,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 */ @@ -6398,7 +6399,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; } } @@ -7868,6 +7869,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, List<Virtual_column_info> new_constraint_list; uint db_create_options= (table->s->db_create_options & ~(HA_OPTION_PACK_RECORD)); + Item::func_processor_rename column_rename_param; uint used_fields, dropped_sys_vers_fields= 0; KEY *key_info=table->key_info; bool rc= TRUE; @@ -7920,6 +7922,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, if (!(used_fields & HA_CREATE_USED_SEQUENCE)) create_info->sequence= table->s->table_type == TABLE_TYPE_SEQUENCE; + column_rename_param.db_name= table->s->db; + column_rename_param.table_name= table->s->table_name; + if (column_rename_param.fields.copy(&alter_info->create_list, thd->mem_root)) + DBUG_RETURN(1); // OOM + restore_record(table, s->default_values); // Empty record for DEFAULT if ((create_info->fields_option_struct= (ha_field_option_struct**) @@ -7974,6 +7981,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, bitmap_set_bit(dropped_fields, field->field_index); continue; } + /* invisible versioning column is dropped automatically on DROP SYSTEM VERSIONING */ if (!drop && field->invisible >= INVISIBLE_SYSTEM && field->flags & VERS_SYSTEM_FIELD && @@ -7983,6 +7991,24 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, (void) delete_statistics_for_column(thd, table, field); continue; } + + /* + If we are doing a rename of a column, update all references in virtual + column expressions, constraints and defaults to use the new column name + */ + if (alter_info->flags & Alter_info::ALTER_RENAME_COLUMN) + { + if (field->vcol_info) + field->vcol_info->expr->walk(&Item::rename_fields_processor, 1, + &column_rename_param); + if (field->check_constraint) + field->check_constraint->expr->walk(&Item::rename_fields_processor, 1, + &column_rename_param); + if (field->default_value) + field->default_value->expr->walk(&Item::rename_fields_processor, 1, + &column_rename_param); + } + /* Check if field is changed */ def_it.rewind(); while ((def=def_it++)) @@ -8443,7 +8469,10 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, } } if (!drop) + { + check->expr->walk(&Item::rename_fields_processor, 1, &column_rename_param); new_constraint_list.push_back(check, thd->mem_root); + } } } /* Add new constraints */ @@ -10555,11 +10584,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 3b40ba52b3d..29bf7aeb205 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1368,11 +1368,12 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db, List_iterator_fast<LEX_CSTRING> it_connection_cl_name(trigger_list->connection_cl_names); List_iterator_fast<LEX_CSTRING> 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= thd->db; thd->reset_db(db); @@ -1589,6 +1590,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db, } thd->reset_db(&save_db); thd->lex= old_lex; + thd->stmt_lex= old_stmt_lex; thd->spcont= save_spcont; thd->variables.sql_mode= save_sql_mode; @@ -1602,6 +1604,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *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); diff --git a/sql/sql_type.cc b/sql/sql_type.cc index d402db8d4e7..9e4c53b8849 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -125,6 +125,15 @@ bool Type_handler_data::init() Type_handler_data *type_handler_data= NULL; +void Time::make_from_item(Item *item) +{ + if (item->get_time(this)) + time_type= MYSQL_TIMESTAMP_NONE; + else + valid_MYSQL_TIME_to_valid_value(); +} + + void Type_std_attributes::set(const Field *field) { decimals= field->decimals(); @@ -2696,6 +2705,12 @@ Type_handler_int_result::Item_get_cache(THD *thd, const Item *item) const } Item_cache * +Type_handler_year::Item_get_cache(THD *thd, const Item *item) const +{ + return new (thd->mem_root) Item_cache_year(thd); +} + +Item_cache * Type_handler_real_result::Item_get_cache(THD *thd, const Item *item) const { return new (thd->mem_root) Item_cache_real(thd); @@ -3221,6 +3236,53 @@ bool Type_handler_string_result::Item_val_bool(Item *item) const /*************************************************************************/ +bool Type_handler_int_result::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + return item->get_date_from_int(ltime, fuzzydate); +} + + +bool Type_handler_year::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + return item->get_date_from_year(ltime, fuzzydate); +} + + +bool Type_handler_real_result::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + return item->get_date_from_real(ltime, fuzzydate); +} + + +bool Type_handler_decimal_result::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + return item->get_date_from_decimal(ltime, fuzzydate); +} + + +bool Type_handler_string_result::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + return item->get_date_from_string(ltime, fuzzydate); +} + + +bool Type_handler_temporal_result::Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const +{ + DBUG_ASSERT(0); // Temporal type items must implement native get_date() + item->null_value= true; + set_zero_time(ltime, mysql_timestamp_type()); + return true; +} + + +/*************************************************************************/ + longlong Type_handler_real_result:: Item_val_int_signed_typecast(Item *item) const { @@ -3936,7 +3998,7 @@ bool Type_handler_string_result:: ::get_date() can be called for non-temporal values, for example, SELECT MONTH(GREATEST("2011-11-21", "2010-10-09")) */ - return func->Item::get_date(ltime, fuzzydate); + return func->get_date_from_string(ltime, fuzzydate); } @@ -3944,7 +4006,7 @@ bool Type_handler_numeric:: Item_func_min_max_get_date(Item_func_min_max *func, MYSQL_TIME *ltime, ulonglong fuzzydate) const { - return func->Item::get_date(ltime, fuzzydate); + return Item_get_date(func, ltime, fuzzydate); } @@ -3955,6 +4017,13 @@ bool Type_handler_temporal_result:: return func->get_date_native(ltime, fuzzydate); } +bool Type_handler_time_common:: + Item_func_min_max_get_date(Item_func_min_max *func, + MYSQL_TIME *ltime, ulonglong fuzzydate) const +{ + return func->get_time_native(ltime); +} + /***************************************************************************/ /** diff --git a/sql/sql_type.h b/sql/sql_type.h index ac95c5a9c88..3c4ed054bb6 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -74,6 +74,127 @@ struct Schema_specification_st; struct TABLE; struct SORT_FIELD_ATTR; + +/** + Class Time is designed to store valid TIME values. + + 1. Valid value: + a. MYSQL_TIMESTAMP_TIME - a valid TIME within the supported TIME range + b. MYSQL_TIMESTAMP_NONE - an undefined value + + 2. Invalid value (internally only): + a. MYSQL_TIMESTAMP_TIME outside of the supported TIME range + a. MYSQL_TIMESTAMP_{DATE|DATETIME|ERROR} + + Temporarily Time is allowed to have an invalid value, but only internally, + during initialization time. All constructors and modification methods must + leave the Time value as described above (see "Valid values"). + + Time derives from MYSQL_TIME privately to make sure it is accessed + externally only in the valid state. +*/ +class Time: private MYSQL_TIME +{ + bool is_valid_value_slow() const + { + return time_type == MYSQL_TIMESTAMP_NONE || is_valid_time_slow(); + } + bool is_valid_time_slow() const + { + return time_type == MYSQL_TIMESTAMP_TIME && + year == 0 && month == 0 && day == 0 && + minute <= TIME_MAX_MINUTE && + second <= TIME_MAX_SECOND && + second_part <= TIME_MAX_SECOND_PART; + } + + /* + Convert a valid DATE or DATETIME to TIME. + Before this call, "this" must be a valid DATE or DATETIME value, + e.g. returned from Item::get_date(). + After this call, "this" is a valid TIME value. + */ + void valid_datetime_to_valid_time() + { + DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATE || + time_type == MYSQL_TIMESTAMP_DATETIME); + /* + Make sure that day and hour are valid, so the result hour value + after mixing days to hours does not go out of the valid TIME range. + */ + DBUG_ASSERT(day < 32); + DBUG_ASSERT(hour < 24); + if (year == 0 && month == 0) + { + /* + The maximum hour value after mixing days will be 31*24+23=767, + which is within the supported TIME range. + Thus no adjust_time_range_or_invalidate() is needed here. + */ + hour+= day * 24; + } + year= month= day= 0; + time_type= MYSQL_TIMESTAMP_TIME; + DBUG_ASSERT(is_valid_time_slow()); + } + /** + Convert valid DATE/DATETIME to valid TIME if needed. + This method is called after Item::get_date(), + which can return only valid TIME/DATE/DATETIME values. + Before this call, "this" is: + - either a valid TIME/DATE/DATETIME value + (within the supported range for the corresponding type), + - or MYSQL_TIMESTAMP_NONE + After this call, "this" is: + - either a valid TIME (within the supported TIME range), + - or MYSQL_TIMESTAMP_NONE + */ + void valid_MYSQL_TIME_to_valid_value() + { + switch (time_type) { + case MYSQL_TIMESTAMP_DATE: + case MYSQL_TIMESTAMP_DATETIME: + valid_datetime_to_valid_time(); + break; + case MYSQL_TIMESTAMP_NONE: + break; + case MYSQL_TIMESTAMP_ERROR: + set_zero_time(this, MYSQL_TIMESTAMP_TIME); + break; + case MYSQL_TIMESTAMP_TIME: + DBUG_ASSERT(is_valid_time_slow()); + break; + } + } + void make_from_item(class Item *item); +public: + Time() { time_type= MYSQL_TIMESTAMP_NONE; } + Time(Item *item) { make_from_item(item); } + bool is_valid_time() const + { + DBUG_ASSERT(is_valid_value_slow()); + return time_type == MYSQL_TIMESTAMP_TIME; + } + void copy_to_mysql_time(MYSQL_TIME *ltime) const + { + DBUG_ASSERT(is_valid_time_slow()); + *ltime= *this; + } + int cmp(const Time *other) const + { + DBUG_ASSERT(is_valid_time_slow()); + DBUG_ASSERT(other->is_valid_time_slow()); + longlong p0= pack_time(this); + longlong p1= pack_time(other); + if (p0 < p1) + return -1; + if (p0 > p1) + return 1; + return 0; + } +}; + + /* Flags for collation aggregation modes, used in TDCollation::agg(): @@ -906,6 +1027,8 @@ public: bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const= 0; virtual bool Item_val_bool(Item *item) const= 0; + virtual bool Item_get_date(Item *item, MYSQL_TIME *ltime, + ulonglong fuzzydate) const= 0; virtual longlong Item_val_int_signed_typecast(Item *item) const= 0; virtual longlong Item_val_int_unsigned_typecast(Item *item) const= 0; @@ -1168,6 +1291,11 @@ public: DBUG_ASSERT(0); return false; } + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const + { + DBUG_ASSERT(0); + return true; + } longlong Item_val_int_signed_typecast(Item *item) const { DBUG_ASSERT(0); @@ -1374,6 +1502,7 @@ public: bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const; bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const; bool Item_val_bool(Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -1452,6 +1581,7 @@ public: bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; bool Item_val_bool(Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -1520,6 +1650,7 @@ public: bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; bool Item_val_bool(Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -1590,6 +1721,7 @@ public: bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; bool Item_val_bool(Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -1703,6 +1835,7 @@ public: bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const; bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const; bool Item_val_bool(Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; longlong Item_val_int_signed_typecast(Item *item) const; longlong Item_val_int_unsigned_typecast(Item *item) const; String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const; @@ -1956,6 +2089,8 @@ public: const Record_addr &addr, const Type_all_attributes &attr, TABLE *table) const; + Item_cache *Item_get_cache(THD *thd, const Item *item) const; + bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const; }; @@ -2099,6 +2234,8 @@ public: Type_handler_hybrid_field_type *, Type_all_attributes *atrr, Item **items, uint nitems) const; + bool Item_func_min_max_get_date(Item_func_min_max*, + MYSQL_TIME *, ulonglong fuzzydate) const; Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const; bool set_comparator_func(Arg_comparator *cmp) const; cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index c9b011130a1..a14c5dd4bd5 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -1790,22 +1790,6 @@ void st_select_lex_unit::reinit_exec_mechanism() { prepared= optimized= optimized_2= executed= 0; optimize_started= 0; -#ifndef DBUG_OFF - if (is_unit_op()) - { - 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 70a4572cd34..b84dc46cae6 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1207,8 +1207,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); } @@ -1362,7 +1360,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 @@ -1397,9 +1395,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/sql_yacc.yy b/sql/sql_yacc.yy index 9cb52ffd432..f7c69af45a2 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -8113,7 +8113,8 @@ alter_list_item: | CHANGE opt_column opt_if_exists_table_element field_ident field_spec opt_place { - Lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN; + Lex->alter_info.flags|= (Alter_info::ALTER_CHANGE_COLUMN | + Alter_info::ALTER_RENAME_COLUMN); Lex->create_last_non_select_table= Lex->last_table(); $5->change= $4; $5->after= $6; diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 48e778f1661..dd84847387a 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -7656,7 +7656,8 @@ alter_list_item: | CHANGE opt_column opt_if_exists_table_element field_ident field_spec opt_place { - Lex->alter_info.flags|= Alter_info::ALTER_CHANGE_COLUMN; + Lex->alter_info.flags|= (Alter_info::ALTER_CHANGE_COLUMN | + Alter_info::ALTER_RENAME_COLUMN); Lex->create_last_non_select_table= Lex->last_table(); $5->change= $4; $5->after= $6; diff --git a/sql/table.cc b/sql/table.cc index 1d3177fb017..a1129d48b52 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1631,9 +1631,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); @@ -3211,6 +3212,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); } for (i= 0; i < 3;) @@ -3219,6 +3221,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, if (++i < records) record+= share->rec_buff_length; } + 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/threadpool_generic.cc b/sql/threadpool_generic.cc index 73274ff12a4..04a72034e5e 100644 --- a/sql/threadpool_generic.cc +++ b/sql/threadpool_generic.cc @@ -1695,10 +1695,9 @@ int TP_pool_generic::set_pool_size(uint size) if(!success) { sql_print_error("io_poll_create() failed, errno=%d\n", errno); - break; } } - mysql_mutex_unlock(&all_groups[i].mutex); + mysql_mutex_unlock(&group->mutex); if (!success) { group_count= i; diff --git a/sql/transaction.cc b/sql/transaction.cc index a11ad13a7dc..d8d435e826a 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -630,12 +630,8 @@ bool trans_savepoint(THD *thd, LEX_CSTRING 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); @@ -710,12 +706,8 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_CSTRING 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 50094ceed47..7bb08cfbf7b 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 @@ -379,6 +379,14 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING *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->str); + 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 9c00f9fdaf6..41044085625 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -29,9 +29,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; @@ -68,7 +69,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); } } @@ -629,8 +634,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) @@ -912,7 +917,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" |