summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt2
-rw-r--r--sql/contributors.h3
-rw-r--r--sql/field.cc11
-rw-r--r--sql/field.h2
-rw-r--r--sql/field_conv.cc6
-rw-r--r--sql/ha_partition.cc9
-rw-r--r--sql/ha_partition.h2
-rw-r--r--sql/handler.cc15
-rw-r--r--sql/handler.h12
-rw-r--r--sql/item.cc188
-rw-r--r--sql/item.h83
-rw-r--r--sql/item_cmpfunc.cc45
-rw-r--r--sql/item_cmpfunc.h6
-rw-r--r--sql/item_func.cc52
-rw-r--r--sql/item_func.h23
-rw-r--r--sql/item_row.h5
-rw-r--r--sql/item_strfunc.cc233
-rw-r--r--sql/item_strfunc.h33
-rw-r--r--sql/item_subselect.cc7
-rw-r--r--sql/item_subselect.h2
-rw-r--r--sql/item_sum.h20
-rw-r--r--sql/item_timefunc.h8
-rw-r--r--sql/item_windowfunc.cc16
-rw-r--r--sql/item_windowfunc.h24
-rw-r--r--sql/item_xmlfunc.cc10
-rw-r--r--sql/item_xmlfunc.h1
-rw-r--r--sql/key.cc6
-rw-r--r--sql/log_event.cc6
-rw-r--r--sql/mf_iocache_encr.cc5
-rw-r--r--sql/mysqld.cc111
-rw-r--r--sql/mysqld.h10
-rw-r--r--sql/net_serv.cc8
-rw-r--r--sql/opt_range.cc2
-rw-r--r--sql/procedure.h4
-rw-r--r--sql/sp.cc1
-rw-r--r--sql/sp_head.cc38
-rw-r--r--sql/sp_head.h3
-rw-r--r--sql/sql_acl.cc12
-rw-r--r--sql/sql_admin.cc5
-rw-r--r--sql/sql_alloc.h6
-rw-r--r--sql/sql_alter.h126
-rw-r--r--sql/sql_base.cc10
-rw-r--r--sql/sql_cache.cc20
-rw-r--r--sql/sql_class.cc16
-rw-r--r--sql/sql_class.h45
-rw-r--r--sql/sql_cte.cc16
-rw-r--r--sql/sql_cte.h2
-rw-r--r--sql/sql_cursor.cc2
-rw-r--r--sql/sql_derived.cc22
-rw-r--r--sql/sql_explain.h6
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_join_cache.cc2
-rw-r--r--sql/sql_lex.cc5
-rw-r--r--sql/sql_lex.h17
-rw-r--r--sql/sql_lifo_buffer.h4
-rw-r--r--sql/sql_list.cc18
-rw-r--r--sql/sql_list.h5
-rw-r--r--sql/sql_parse.cc13
-rw-r--r--sql/sql_partition.cc12
-rw-r--r--sql/sql_plugin.cc5
-rw-r--r--sql/sql_prepare.cc21
-rw-r--r--sql/sql_select.cc76
-rw-r--r--sql/sql_select.h4
-rw-r--r--sql/sql_show.cc19
-rw-r--r--sql/sql_string.h7
-rw-r--r--sql/sql_table.cc36
-rw-r--r--sql/sql_trigger.cc7
-rw-r--r--sql/sql_type.cc73
-rw-r--r--sql/sql_type.h137
-rw-r--r--sql/sql_union.cc16
-rw-r--r--sql/sql_view.cc7
-rw-r--r--sql/sql_yacc.yy3
-rw-r--r--sql/sql_yacc_ora.yy3
-rw-r--r--sql/table.cc8
-rw-r--r--sql/threadpool_generic.cc3
-rw-r--r--sql/transaction.cc12
-rw-r--r--sql/unireg.cc10
-rw-r--r--sql/wsrep_sst.cc19
-rw-r--r--sql/wsrep_sst.h3
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> &parameters)
{
+ 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,
&copy);
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"