summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2017-11-30 08:16:37 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2017-11-30 08:16:37 +0200
commit7cb3520c0632ad912b309489ad86a90f9fc9bd0b (patch)
treeff8e6b8fdf5e9cacdfe914790e480bc3bad2ad85 /sql
parent51b30586ea999744de6a15146257f2976825781e (diff)
parent5b697c5a23ed7322b5b746b61e3ec66b510ca134 (diff)
downloadmariadb-git-7cb3520c0632ad912b309489ad86a90f9fc9bd0b.tar.gz
Merge bb-10.2-ext into 10.3
Diffstat (limited to 'sql')
-rw-r--r--sql/filesort.cc4
-rw-r--r--sql/item.cc534
-rw-r--r--sql/item.h226
-rw-r--r--sql/item_cmpfunc.cc8
-rw-r--r--sql/item_cmpfunc.h2
-rw-r--r--sql/item_func.cc4
-rw-r--r--sql/item_geofunc.cc3
-rw-r--r--sql/item_jsonfunc.cc10
-rw-r--r--sql/item_row.cc2
-rw-r--r--sql/item_row.h4
-rw-r--r--sql/item_subselect.cc1
-rw-r--r--sql/item_subselect.h1
-rw-r--r--sql/item_sum.cc6
-rw-r--r--sql/item_timefunc.cc5
-rw-r--r--sql/item_timefunc.h11
-rw-r--r--sql/item_windowfunc.cc4
-rw-r--r--sql/lex.h1
-rw-r--r--sql/log.cc217
-rw-r--r--sql/log.h7
-rw-r--r--sql/mysqld.cc3
-rw-r--r--sql/opt_subselect.cc2
-rw-r--r--sql/partition_info.cc3
-rw-r--r--sql/protocol.cc1
-rw-r--r--sql/rpl_gtid.cc151
-rw-r--r--sql/rpl_gtid.h9
-rw-r--r--sql/share/errmsg-utf8.txt9
-rw-r--r--sql/sp_head.cc46
-rw-r--r--sql/sp_head.h5
-rw-r--r--sql/sp_rcontext.cc10
-rw-r--r--sql/sp_rcontext.h2
-rw-r--r--sql/spatial.cc35
-rw-r--r--sql/spatial.h1
-rw-r--r--sql/sql_acl.cc5
-rw-r--r--sql/sql_alter.h6
-rw-r--r--sql/sql_class.cc7
-rw-r--r--sql/sql_class.h17
-rw-r--r--sql/sql_cte.cc3
-rw-r--r--sql/sql_get_diagnostics.cc3
-rw-r--r--sql/sql_lex.cc44
-rw-r--r--sql/sql_lex.h10
-rw-r--r--sql/sql_parse.cc26
-rw-r--r--sql/sql_prepare.cc224
-rw-r--r--sql/sql_reload.cc5
-rw-r--r--sql/sql_repl.cc68
-rw-r--r--sql/sql_repl.h1
-rw-r--r--sql/sql_select.cc33
-rw-r--r--sql/sql_sequence.cc4
-rw-r--r--sql/sql_show.cc5
-rw-r--r--sql/sql_type.cc165
-rw-r--r--sql/sql_type.h38
-rw-r--r--sql/sql_union.cc6
-rw-r--r--sql/sql_yacc.yy160
-rw-r--r--sql/sql_yacc_ora.yy32
-rw-r--r--sql/threadpool_generic.cc129
-rw-r--r--sql/wsrep_hton.cc3
-rw-r--r--sql/wsrep_mysqld.cc2
-rw-r--r--sql/wsrep_var.cc3
57 files changed, 1601 insertions, 725 deletions
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 3c33f06d6cf..b762773b11e 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -826,11 +826,11 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
MY_BITMAP *tmp_write_set= sort_form->write_set;
MY_BITMAP *tmp_vcol_set= sort_form->vcol_set;
- if (select->cond->with_subselect)
+ if (select->cond->with_subquery())
sort_form->column_bitmaps_set(save_read_set, save_write_set,
save_vcol_set);
write_record= (select->skip_record(thd) > 0);
- if (select->cond->with_subselect)
+ if (select->cond->with_subquery())
sort_form->column_bitmaps_set(tmp_read_set,
tmp_write_set,
tmp_vcol_set);
diff --git a/sql/item.cc b/sql/item.cc
index b344a9068db..3ed43de5739 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -538,7 +538,6 @@ Item::Item(THD *thd):
marker= 0;
maybe_null=null_value=with_sum_func=with_window_func=with_field=0;
in_rollup= 0;
- with_subselect= 0;
/* Initially this item is not attached to any JOIN_TAB. */
join_tab_idx= MAX_TABLES;
@@ -583,8 +582,7 @@ Item::Item(THD *thd, Item *item):
with_window_func(item->with_window_func),
with_field(item->with_field),
fixed(item->fixed),
- is_autogenerated_name(item->is_autogenerated_name),
- with_subselect(item->has_subquery())
+ is_autogenerated_name(item->is_autogenerated_name)
{
next= thd->free_list; // Put in free list
thd->free_list= this;
@@ -3714,20 +3712,6 @@ Item *Item_null::clone_item(THD *thd)
/*********************** Item_param related ******************************/
-/**
- Default function of Item_param::set_param_func, so in case
- of malformed packet the server won't SIGSEGV.
-*/
-
-static void
-default_set_param_func(Item_param *param,
- uchar **pos __attribute__((unused)),
- ulong len __attribute__((unused)))
-{
- param->set_null();
-}
-
-
Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg,
uint pos_in_query_arg, uint len_in_query_arg):
Item_basic_value(thd),
@@ -3745,8 +3729,8 @@ Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg,
state(NO_VALUE),
/* Don't pretend to be a literal unless value for this item is set. */
item_type(PARAM_ITEM),
+ m_empty_string_is_null(false),
indicator(STMT_INDICATOR_NONE),
- set_param_func(default_set_param_func),
m_out_param_info(NULL),
/*
Set m_is_settable_routine_parameter to "true" by default.
@@ -3787,8 +3771,10 @@ void Item_param::set_null()
void Item_param::set_int(longlong i, uint32 max_length_arg)
{
DBUG_ENTER("Item_param::set_int");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == INT_RESULT);
value.integer= (longlong) i;
- state= INT_VALUE;
+ state= SHORT_DATA_VALUE;
+ collation.set_numeric();
max_length= max_length_arg;
decimals= 0;
maybe_null= 0;
@@ -3799,8 +3785,10 @@ void Item_param::set_int(longlong i, uint32 max_length_arg)
void Item_param::set_double(double d)
{
DBUG_ENTER("Item_param::set_double");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == REAL_RESULT);
value.real= d;
- state= REAL_VALUE;
+ state= SHORT_DATA_VALUE;
+ collation.set_numeric();
max_length= DBL_DIG + 8;
decimals= NOT_FIXED_DEC;
maybe_null= 0;
@@ -3825,13 +3813,15 @@ void Item_param::set_decimal(const char *str, ulong length)
{
char *end;
DBUG_ENTER("Item_param::set_decimal");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == DECIMAL_RESULT);
end= (char*) str+length;
- str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value, &end);
- state= DECIMAL_VALUE;
- decimals= decimal_value.frac;
+ str2my_decimal(E_DEC_FATAL_ERROR, str, &value.m_decimal, &end);
+ state= SHORT_DATA_VALUE;
+ decimals= value.m_decimal.frac;
+ collation.set_numeric();
max_length=
- my_decimal_precision_to_length_no_truncation(decimal_value.precision(),
+ my_decimal_precision_to_length_no_truncation(value.m_decimal.precision(),
decimals, unsigned_flag);
maybe_null= 0;
fix_type(Item::DECIMAL_ITEM);
@@ -3840,13 +3830,15 @@ void Item_param::set_decimal(const char *str, ulong length)
void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg)
{
- state= DECIMAL_VALUE;
+ DBUG_ASSERT(value.type_handler()->cmp_type() == DECIMAL_RESULT);
+ state= SHORT_DATA_VALUE;
- my_decimal2decimal(dv, &decimal_value);
+ my_decimal2decimal(dv, &value.m_decimal);
- decimals= (uint8) decimal_value.frac;
+ decimals= (uint8) value.m_decimal.frac;
+ collation.set_numeric();
unsigned_flag= unsigned_arg;
- max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
+ max_length= my_decimal_precision_to_length(value.m_decimal.intg + decimals,
decimals, unsigned_flag);
fix_type(Item::DECIMAL_ITEM);
}
@@ -3854,7 +3846,8 @@ void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg)
void Item_param::fix_temporal(uint32 max_length_arg, uint decimals_arg)
{
- state= TIME_VALUE;
+ state= SHORT_DATA_VALUE;
+ collation.set_numeric();
max_length= max_length_arg;
decimals= decimals_arg;
fix_type(Item::DATE_ITEM);
@@ -3864,6 +3857,7 @@ void Item_param::fix_temporal(uint32 max_length_arg, uint decimals_arg)
void Item_param::set_time(const MYSQL_TIME *tm,
uint32 max_length_arg, uint decimals_arg)
{
+ DBUG_ASSERT(value.type_handler()->cmp_type() == TIME_RESULT);
value.time= *tm;
fix_temporal(max_length_arg, decimals_arg);
}
@@ -3886,6 +3880,7 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
uint32 max_length_arg)
{
DBUG_ENTER("Item_param::set_time");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == TIME_RESULT);
value.time= *tm;
value.time.time_type= time_type;
@@ -3904,18 +3899,34 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
}
-bool Item_param::set_str(const char *str, ulong length)
+bool Item_param::set_str(const char *str, ulong length,
+ CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
DBUG_ENTER("Item_param::set_str");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == STRING_RESULT);
/*
Assign string with no conversion: data is converted only after it's
been written to the binary log.
*/
uint dummy_errors;
- if (str_value.copy(str, length, &my_charset_bin, &my_charset_bin,
- &dummy_errors))
+ if (value.m_string.copy(str, length, fromcs, tocs, &dummy_errors))
DBUG_RETURN(TRUE);
- state= STRING_VALUE;
+ /*
+ Set str_value_ptr to make sure it's in sync with str_value.
+ This is needed in case if we're called from Item_param::set_value(),
+ from the code responsible for setting OUT parameters in
+ sp_head::execute_procedure(). This makes sure that
+ Protocol_binary::send_out_parameters() later gets a valid value
+ from Item_param::val_str().
+ Note, for IN parameters, Item_param::convert_str_value() will be called
+ later, which will convert the value from the client character set to the
+ connection character set, and will reset both str_value and str_value_ptr.
+ */
+ value.m_string_ptr.set(value.m_string.ptr(),
+ value.m_string.length(),
+ value.m_string.charset());
+ state= SHORT_DATA_VALUE;
+ collation.set(tocs, DERIVATION_COERCIBLE);
max_length= length;
maybe_null= 0;
/* max_length and decimals are set after charset conversion */
@@ -3928,6 +3939,7 @@ bool Item_param::set_str(const char *str, ulong length)
bool Item_param::set_longdata(const char *str, ulong length)
{
DBUG_ENTER("Item_param::set_longdata");
+ DBUG_ASSERT(value.type_handler()->cmp_type() == STRING_RESULT);
/*
If client character set is multibyte, end of long data packet
@@ -3938,7 +3950,7 @@ bool Item_param::set_longdata(const char *str, ulong length)
(here), and first have to concatenate all pieces together,
write query to the binary log and only then perform conversion.
*/
- if (str_value.length() + length > max_long_data_size)
+ if (value.m_string.length() + length > max_long_data_size)
{
my_message(ER_UNKNOWN_ERROR,
"Parameter of prepared statement which is set through "
@@ -3948,7 +3960,7 @@ bool Item_param::set_longdata(const char *str, ulong length)
DBUG_RETURN(true);
}
- if (str_value.append(str, length, &my_charset_bin))
+ if (value.m_string.append(str, length, &my_charset_bin))
DBUG_RETURN(TRUE);
state= LONG_DATA_VALUE;
maybe_null= 0;
@@ -4011,16 +4023,16 @@ bool Item_param::set_from_item(THD *thd, Item *item)
else
{
unsigned_flag= item->unsigned_flag;
- set_int(val, MY_INT64_NUM_DECIMAL_DIGITS);
- set_handler_by_result_type(item->result_type());
- DBUG_RETURN(!unsigned_flag && value.integer < 0 ? 1 : 0);
+ set_handler(item->type_handler());
+ DBUG_RETURN(set_limit_clause_param(val));
}
}
struct st_value tmp;
if (!item->save_in_value(&tmp))
{
- if (item->type_handler()->Item_param_set_from_value(thd, this, item, &tmp))
- DBUG_RETURN(true);
+ const Type_handler *h= item->type_handler();
+ set_handler(h);
+ DBUG_RETURN(set_value(thd, item, &tmp, h));
}
else
set_null();
@@ -4040,16 +4052,16 @@ void Item_param::reset()
{
DBUG_ENTER("Item_param::reset");
/* Shrink string buffer if it's bigger than max possible CHAR column */
- if (str_value.alloced_length() > MAX_CHAR_WIDTH)
- str_value.free();
+ if (value.m_string.alloced_length() > MAX_CHAR_WIDTH)
+ value.m_string.free();
else
- str_value.length(0);
- str_value_ptr.length(0);
+ value.m_string.length(0);
+ value.m_string_ptr.length(0);
/*
We must prevent all charset conversions until data has been written
to the binary log.
*/
- str_value.set_charset(&my_charset_bin);
+ value.m_string.set_charset(&my_charset_bin);
collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
state= NO_VALUE;
maybe_null= 1;
@@ -4078,19 +4090,9 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
Garbage (e.g. in case of a memory overrun) is handled after the switch.
*/
switch (state) {
- case INT_VALUE:
- return field->store(value.integer, unsigned_flag);
- case REAL_VALUE:
- return field->store(value.real);
- case DECIMAL_VALUE:
- return field->store_decimal(&decimal_value);
- case TIME_VALUE:
- field->store_time_dec(&value.time, decimals);
- return 0;
- case STRING_VALUE:
+ case SHORT_DATA_VALUE:
case LONG_DATA_VALUE:
- return field->store(str_value.ptr(), str_value.length(),
- str_value.charset());
+ return value.type_handler()->Item_save_in_field(this, field, no_conversions);
case NULL_VALUE:
return set_field_to_null_with_conversions(field, no_conversions);
case DEFAULT_VALUE:
@@ -4110,6 +4112,28 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
}
+bool Item_param::can_return_value() const
+{
+ // There's no "default". See comments in Item_param::save_in_field().
+ switch (state) {
+ case SHORT_DATA_VALUE:
+ case LONG_DATA_VALUE:
+ return true;
+ case IGNORE_VALUE:
+ case DEFAULT_VALUE:
+ invalid_default_param();
+ // fall through
+ case NULL_VALUE:
+ return false;
+ case NO_VALUE:
+ DBUG_ASSERT(0); // Should not be possible
+ return false;
+ }
+ DBUG_ASSERT(0); // Garbage
+ return false;
+}
+
+
void Item_param::invalid_default_param() const
{
my_message(ER_INVALID_DEFAULT_PARAM,
@@ -4119,7 +4143,14 @@ void Item_param::invalid_default_param() const
bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate)
{
- if (state == TIME_VALUE)
+ /*
+ LIMIT clause parameter should not call get_date()
+ For non-LIMIT parameters, handlers must be the same.
+ */
+ DBUG_ASSERT(type_handler()->result_type() ==
+ value.type_handler()->result_type());
+ if (state == SHORT_DATA_VALUE &&
+ value.type_handler()->cmp_type() == TIME_RESULT)
{
*res= value.time;
return 0;
@@ -4128,157 +4159,117 @@ bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate)
}
-double Item_param::val_real()
+double Item_param::PValue::val_real() const
{
- // There's no "default". See comments in Item_param::save_in_field().
- switch (state) {
- case REAL_VALUE:
- return value.real;
- case INT_VALUE:
- return (double) value.integer;
- case DECIMAL_VALUE:
+ switch (type_handler()->cmp_type()) {
+ case REAL_RESULT:
+ return real;
+ case INT_RESULT:
+ return (double) integer;
+ case DECIMAL_RESULT:
{
double result;
- my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result);
+ my_decimal2double(E_DEC_FATAL_ERROR, &m_decimal, &result);
return result;
}
- case STRING_VALUE:
- case LONG_DATA_VALUE:
- {
- return double_from_string_with_check(&str_value);
- }
- case TIME_VALUE:
+ case STRING_RESULT:
+ return double_from_string_with_check(&m_string);
+ case TIME_RESULT:
/*
This works for example when user says SELECT ?+0.0 and supplies
time value for the placeholder.
*/
- return TIME_to_double(&value.time);
- case IGNORE_VALUE:
- case DEFAULT_VALUE:
- invalid_default_param();
- // fall through
- case NULL_VALUE:
- return 0.0;
- case NO_VALUE:
- DBUG_ASSERT(0); // Should not be possible
- return 0.0;
+ return TIME_to_double(&time);
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
}
- DBUG_ASSERT(0); // Garbage
return 0.0;
-}
+}
-longlong Item_param::val_int()
-{
- // There's no "default". See comments in Item_param::save_in_field().
- switch (state) {
- case REAL_VALUE:
- return (longlong) rint(value.real);
- case INT_VALUE:
- return value.integer;
- case DECIMAL_VALUE:
+longlong Item_param::PValue::val_int(const Type_std_attributes *attr) const
+{
+ switch (type_handler()->cmp_type()) {
+ case REAL_RESULT:
+ return (longlong) rint(real);
+ case INT_RESULT:
+ return integer;
+ case DECIMAL_RESULT:
{
longlong i;
- my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &i);
+ my_decimal2int(E_DEC_FATAL_ERROR, &m_decimal, attr->unsigned_flag, &i);
return i;
}
- case STRING_VALUE:
- case LONG_DATA_VALUE:
- {
- return longlong_from_string_with_check(&str_value);
- }
- case TIME_VALUE:
- return (longlong) TIME_to_ulonglong(&value.time);
- case IGNORE_VALUE:
- case DEFAULT_VALUE:
- invalid_default_param();
- // fall through
- case NULL_VALUE:
- return 0;
- case NO_VALUE:
- DBUG_ASSERT(0); // Should not be possible
- return 0;
+ case STRING_RESULT:
+ return longlong_from_string_with_check(&m_string);
+ case TIME_RESULT:
+ return (longlong) TIME_to_ulonglong(&time);
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
}
- DBUG_ASSERT(0); // Garbage
return 0;
}
-my_decimal *Item_param::val_decimal(my_decimal *dec)
+my_decimal *Item_param::PValue::val_decimal(my_decimal *dec,
+ const Type_std_attributes *attr)
{
- // There's no "default". See comments in Item_param::save_in_field().
- switch (state) {
- case DECIMAL_VALUE:
- return &decimal_value;
- case REAL_VALUE:
- double2my_decimal(E_DEC_FATAL_ERROR, value.real, dec);
+ switch (type_handler()->cmp_type()) {
+ case DECIMAL_RESULT:
+ return &m_decimal;
+ case REAL_RESULT:
+ double2my_decimal(E_DEC_FATAL_ERROR, real, dec);
return dec;
- case INT_VALUE:
- int2my_decimal(E_DEC_FATAL_ERROR, value.integer, unsigned_flag, dec);
+ case INT_RESULT:
+ int2my_decimal(E_DEC_FATAL_ERROR, integer, attr->unsigned_flag, dec);
return dec;
- case STRING_VALUE:
- case LONG_DATA_VALUE:
- return decimal_from_string_with_check(dec, &str_value);
- case TIME_VALUE:
- {
- return TIME_to_my_decimal(&value.time, dec);
- }
- case IGNORE_VALUE:
- case DEFAULT_VALUE:
- invalid_default_param();
- // fall through
- case NULL_VALUE:
- return 0;
- case NO_VALUE:
- DBUG_ASSERT(0); // Should not be possible
- return 0;
+ case STRING_RESULT:
+ return decimal_from_string_with_check(dec, &m_string);
+ case TIME_RESULT:
+ return TIME_to_my_decimal(&time, dec);
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
}
- DBUG_ASSERT(0); // Gabrage
return 0;
}
-String *Item_param::val_str(String* str)
-{
- // There's no "default". See comments in Item_param::save_in_field().
- switch (state) {
- case STRING_VALUE:
- case LONG_DATA_VALUE:
- return &str_value_ptr;
- case REAL_VALUE:
- str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
+String *Item_param::PValue::val_str(String *str,
+ const Type_std_attributes *attr)
+{
+ switch (type_handler()->cmp_type()) {
+ case STRING_RESULT:
+ return &m_string_ptr;
+ case REAL_RESULT:
+ str->set_real(real, NOT_FIXED_DEC, &my_charset_bin);
return str;
- case INT_VALUE:
- str->set(value.integer, &my_charset_bin);
+ case INT_RESULT:
+ str->set(integer, &my_charset_bin);
return str;
- case DECIMAL_VALUE:
- if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
- 0, 0, 0, str) <= 1)
+ case DECIMAL_RESULT:
+ if (my_decimal2string(E_DEC_FATAL_ERROR, &m_decimal, 0, 0, 0, str) <= 1)
return str;
return NULL;
- case TIME_VALUE:
+ case TIME_RESULT:
{
if (str->reserve(MAX_DATE_STRING_REP_LENGTH))
- break;
- str->length((uint) my_TIME_to_str(&value.time, (char*) str->ptr(),
- decimals));
+ return NULL;
+ str->length((uint) my_TIME_to_str(&time, (char*) str->ptr(),
+ attr->decimals));
str->set_charset(&my_charset_bin);
return str;
}
- case IGNORE_VALUE:
- case DEFAULT_VALUE:
- invalid_default_param();
- // fall through
- case NULL_VALUE:
- return NULL;
- case NO_VALUE:
- DBUG_ASSERT(0); // Should not be possible
- return NULL;
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
}
- DBUG_ASSERT(0); // Garbage
return NULL;
}
+
/**
Return Param item values in string format, for generating the dynamic
query used in update/binary logs.
@@ -4290,32 +4281,31 @@ String *Item_param::val_str(String* str)
that binary log contains wrong statement
*/
-const String *Item_param::query_val_str(THD *thd, String* str) const
+const String *Item_param::value_query_val_str(THD *thd, String *str) const
{
- // There's no "default". See comments in Item_param::save_in_field().
- switch (state) {
- case INT_VALUE:
+ switch (value.type_handler()->cmp_type()) {
+ case INT_RESULT:
str->set_int(value.integer, unsigned_flag, &my_charset_bin);
return str;
- case REAL_VALUE:
+ case REAL_RESULT:
str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
return str;
- case DECIMAL_VALUE:
- if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
+ case DECIMAL_RESULT:
+ if (my_decimal2string(E_DEC_FATAL_ERROR, &value.m_decimal,
0, 0, 0, str) > 1)
return &my_null_string;
return str;
- case TIME_VALUE:
+ case TIME_RESULT:
{
static const uint32 typelen= 9; // "TIMESTAMP" is the longest type name
char *buf, *ptr;
str->length(0);
/*
TODO: in case of error we need to notify replication
- that binary log contains wrong statement
+ that binary log contains wrong statement
*/
if (str->reserve(MAX_DATE_STRING_REP_LENGTH + 3 + typelen))
- break;
+ return NULL;
/* Create date string inplace */
switch (value.time.time_type) {
@@ -4341,15 +4331,29 @@ const String *Item_param::query_val_str(THD *thd, String* str) const
str->length((uint32) (ptr - buf));
return str;
}
- case STRING_VALUE:
- case LONG_DATA_VALUE:
+ case STRING_RESULT:
{
str->length(0);
append_query_string(value.cs_info.character_set_client, str,
- str_value.ptr(), str_value.length(),
+ value.m_string.ptr(), value.m_string.length(),
thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES);
return str;
}
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
+ }
+ return NULL;
+}
+
+
+const String *Item_param::query_val_str(THD *thd, String* str) const
+{
+ // There's no "default". See comments in Item_param::save_in_field().
+ switch (state) {
+ case SHORT_DATA_VALUE:
+ case LONG_DATA_VALUE:
+ return value_query_val_str(thd, str);
case IGNORE_VALUE:
case DEFAULT_VALUE:
return &my_default_string;
@@ -4372,19 +4376,20 @@ const String *Item_param::query_val_str(THD *thd, String* str) const
bool Item_param::convert_str_value(THD *thd)
{
bool rc= FALSE;
- if (state == STRING_VALUE || state == LONG_DATA_VALUE)
+ if ((state == SHORT_DATA_VALUE || state == LONG_DATA_VALUE) &&
+ value.type_handler()->cmp_type() == STRING_RESULT)
{
- rc= value.cs_info.convert_if_needed(thd, &str_value);
+ rc= value.cs_info.convert_if_needed(thd, &value.m_string);
/* Here str_value is guaranteed to be in final_character_set_of_str_value */
/*
str_value_ptr is returned from val_str(). It must be not alloced
to prevent it's modification by val_str() invoker.
*/
- str_value_ptr.set(str_value.ptr(), str_value.length(),
- str_value.charset());
+ value.m_string_ptr.set(value.m_string.ptr(), value.m_string.length(),
+ value.m_string.charset());
/* Synchronize item charset and length with value charset */
- fix_charset_and_length_from_str_value(DERIVATION_COERCIBLE);
+ fix_charset_and_length_from_str_value(value.m_string, DERIVATION_COERCIBLE);
}
return rc;
}
@@ -4393,18 +4398,48 @@ bool Item_param::convert_str_value(THD *thd)
bool Item_param::basic_const_item() const
{
DBUG_ASSERT(fixed || state == NO_VALUE);
- if (state == NO_VALUE || state == TIME_VALUE)
+ if (state == NO_VALUE ||
+ (state == SHORT_DATA_VALUE && type_handler()->cmp_type() == TIME_RESULT))
return FALSE;
return TRUE;
}
+Item *Item_param::value_clone_item(THD *thd)
+{
+ MEM_ROOT *mem_root= thd->mem_root;
+ switch (value.type_handler()->cmp_type()) {
+ case INT_RESULT:
+ return (unsigned_flag ?
+ new (mem_root) Item_uint(thd, name.str, value.integer, max_length) :
+ new (mem_root) Item_int(thd, name.str, value.integer, max_length));
+ case REAL_RESULT:
+ return new (mem_root) Item_float(thd, name.str, value.real, decimals,
+ max_length);
+ case DECIMAL_RESULT:
+ return 0; // Should create Item_decimal. See MDEV-11361.
+ case STRING_RESULT:
+ return new (mem_root) Item_string(thd, name.str,
+ value.m_string.c_ptr_quick(),
+ value.m_string.length(),
+ value.m_string.charset(),
+ collation.derivation,
+ collation.repertoire);
+ case TIME_RESULT:
+ break;
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ break;
+ }
+ return 0;
+}
+
+
/* see comments in the header file */
Item *
Item_param::clone_item(THD *thd)
{
- MEM_ROOT *mem_root= thd->mem_root;
// There's no "default". See comments in Item_param::save_in_field().
switch (state) {
case IGNORE_VALUE:
@@ -4412,24 +4447,13 @@ Item_param::clone_item(THD *thd)
invalid_default_param();
// fall through
case NULL_VALUE:
- return new (mem_root) Item_null(thd, name.str);
- case INT_VALUE:
- return (unsigned_flag ?
- new (mem_root) Item_uint(thd, name.str, value.integer, max_length) :
- new (mem_root) Item_int(thd, name.str, value.integer, max_length));
- case REAL_VALUE:
- return new (mem_root) Item_float(thd, name.str, value.real, decimals,
- max_length);
- case DECIMAL_VALUE:
- return 0; // Should create Item_decimal. See MDEV-11361.
- case STRING_VALUE:
+ return new (thd->mem_root) Item_null(thd, name.str);
+ case SHORT_DATA_VALUE:
case LONG_DATA_VALUE:
- return new (mem_root) Item_string(thd, name.str, str_value.c_ptr_quick(),
- str_value.length(), str_value.charset(),
- collation.derivation,
- collation.repertoire);
- case TIME_VALUE:
- return 0;
+ {
+ DBUG_ASSERT(type_handler()->cmp_type() == value.type_handler()->cmp_type());
+ return value_clone_item(thd);
+ }
case NO_VALUE:
return 0;
}
@@ -4438,6 +4462,24 @@ Item_param::clone_item(THD *thd)
}
+bool Item_param::value_eq(const Item *item, bool binary_cmp) const
+{
+ switch (value.type_handler()->cmp_type()) {
+ case INT_RESULT:
+ return int_eq(value.integer, item);
+ case REAL_RESULT:
+ return real_eq(value.real, item);
+ case STRING_RESULT:
+ return str_eq(&value.m_string, item, binary_cmp);
+ case DECIMAL_RESULT:
+ case TIME_RESULT:
+ case ROW_RESULT:
+ break;
+ }
+ return false;
+}
+
+
bool
Item_param::eq(const Item *item, bool binary_cmp) const
{
@@ -4452,15 +4494,9 @@ Item_param::eq(const Item *item, bool binary_cmp) const
return false;
case NULL_VALUE:
return null_eq(item);
- case INT_VALUE:
- return int_eq(value.integer, item);
- case REAL_VALUE:
- return real_eq(value.real, item);
- case STRING_VALUE:
+ case SHORT_DATA_VALUE:
case LONG_DATA_VALUE:
- return str_eq(&str_value, item, binary_cmp);
- case DECIMAL_VALUE:
- case TIME_VALUE:
+ return value_eq(item, binary_cmp);
case NO_VALUE:
return false;
}
@@ -4521,18 +4557,14 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
{
Type_std_attributes::set(src);
set_handler(src->type_handler());
- set_param_func= src->set_param_func;
item_type= src->item_type;
maybe_null= src->maybe_null;
null_value= src->null_value;
state= src->state;
fixed= src->fixed;
- value= src->value;
- decimal_value.swap(src->decimal_value);
- str_value.swap(src->str_value);
- str_value_ptr.swap(src->str_value_ptr);
+ value.swap(src->value);
}
@@ -4577,65 +4609,21 @@ bool
Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
{
Item *arg= *it;
-
- if (arg->is_null())
+ struct st_value tmp;
+ /*
+ The OUT parameter is bound to some data type.
+ It's important not to touch m_type_handler,
+ to make sure the next mysql_stmt_execute()
+ correctly fetches the value from the client-server protocol,
+ using set_param_func().
+ */
+ if (arg->save_in_value(&tmp) ||
+ set_value(thd, arg, &tmp, arg->type_handler()))
{
set_null();
- return FALSE;
- }
-
- null_value= FALSE;
-
- switch (arg->result_type()) {
- case STRING_RESULT:
- {
- char str_buffer[STRING_BUFFER_USUAL_SIZE];
- String sv_buffer(str_buffer, sizeof(str_buffer), &my_charset_bin);
- String *sv= arg->val_str(&sv_buffer);
-
- if (!sv)
- return TRUE;
-
- set_str(sv->c_ptr_safe(), sv->length());
- str_value_ptr.set(str_value.ptr(),
- str_value.length(),
- str_value.charset());
- collation.set(str_value.charset(), DERIVATION_COERCIBLE);
- decimals= 0;
- break;
- }
-
- case REAL_RESULT:
- set_double(arg->val_real());
- break;
-
- case INT_RESULT:
- set_int(arg->val_int(), arg->max_length);
- break;
-
- case DECIMAL_RESULT:
- {
- my_decimal dv_buf;
- my_decimal *dv= arg->val_decimal(&dv_buf);
-
- if (!dv)
- return TRUE;
-
- set_decimal(dv, !dv->sign());
- break;
- }
-
- default:
- /* That can not happen. */
-
- DBUG_ASSERT(TRUE); // Abort in debug mode.
-
- set_null(); // Set to NULL in release mode.
- return FALSE;
+ return false;
}
-
- set_handler_by_result_type(arg->result_type());
- return FALSE;
+ return null_value= false;
}
@@ -8253,7 +8241,7 @@ Item_cache_wrapper::Item_cache_wrapper(THD *thd, Item *item_arg):
with_sum_func= orig_item->with_sum_func;
with_field= orig_item->with_field;
name= item_arg->name;
- with_subselect= orig_item->with_subselect;
+ m_with_subquery= orig_item->with_subquery();
if ((expr_value= orig_item->get_cache(thd)))
expr_value->setup(thd, orig_item);
diff --git a/sql/item.h b/sql/item.h
index 8aec1b34b94..6f6a2060f90 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -389,6 +389,8 @@ public:
virtual const Send_field *get_out_param_info() const
{ return NULL; }
+
+ virtual Item_param *get_item_param() { return 0; }
};
@@ -699,9 +701,6 @@ public:
bool fixed; /* If item fixed with fix_fields */
bool is_autogenerated_name; /* indicate was name of this Item
autogenerated or set by user */
- bool with_subselect; /* If this item is a subselect or some
- of its arguments is or contains a
- subselect */
// alloc & destruct is done as start of select on THD::mem_root
Item(THD *thd);
/*
@@ -1869,9 +1868,10 @@ public:
virtual bool is_outer_field() const { DBUG_ASSERT(fixed); return FALSE; }
/**
- Checks if this item or any of its decendents contains a subquery.
+ Checks if this item or any of its decendents contains a subquery. This is a
+ replacement of the former Item::has_subquery() and Item::with_subselect.
*/
- virtual bool has_subquery() const { return with_subselect; }
+ virtual bool with_subquery() const { DBUG_ASSERT(fixed); return false; }
Item* set_expr_cache(THD *thd);
@@ -1949,6 +1949,21 @@ inline Item* get_item_copy (THD *thd, T* item)
}
+/*
+ This class is a replacement for the former member Item::with_subselect.
+ Determines if the descendant Item is a subselect or some of
+ its arguments is or contains a subselect.
+*/
+class With_subquery_cache
+{
+protected:
+ bool m_with_subquery;
+public:
+ With_subquery_cache(): m_with_subquery(false) { }
+ void join(const Item *item) { m_with_subquery|= item->with_subquery(); }
+};
+
+
class Type_geometry_attributes
{
uint m_geometry_type;
@@ -2171,7 +2186,8 @@ protected:
uint repertoire() const { return MY_STRING_METADATA::repertoire; }
size_t char_length() const { return MY_STRING_METADATA::char_length; }
};
- void fix_charset_and_length_from_str_value(Derivation dv, Metadata metadata)
+ void fix_charset_and_length(CHARSET_INFO *cs,
+ Derivation dv, Metadata metadata)
{
/*
We have to have a different max_length than 'length' here to
@@ -2180,13 +2196,13 @@ protected:
number of chars for a string of this type because we in Create_field::
divide the max_length with mbmaxlen).
*/
- collation.set(str_value.charset(), dv, metadata.repertoire());
+ collation.set(cs, dv, metadata.repertoire());
fix_char_length(metadata.char_length());
decimals= NOT_FIXED_DEC;
}
- void fix_charset_and_length_from_str_value(Derivation dv)
+ void fix_charset_and_length_from_str_value(const String &str, Derivation dv)
{
- fix_charset_and_length_from_str_value(dv, Metadata(&str_value));
+ fix_charset_and_length(str.charset(), dv, Metadata(&str));
}
Item_basic_value(THD *thd): Item(thd) {}
/*
@@ -3062,12 +3078,27 @@ public:
For example in case of 'SELECT ?' you'll get MYSQL_TYPE_STRING both
in result set and placeholders metadata, no matter what type you will
supply for this placeholder in mysql_stmt_execute.
+
+ Item_param has two Type_handler pointers,
+ which can point to different handlers:
+
+ 1. In the Type_handler_hybrid_field_type member
+ It's initialized in:
+ - Item_param::setup_conversion(), for client-server PS protocol,
+ according to the bind type.
+ - Item_param::set_from_item(), for EXECUTE and EXECUTE IMMEDIATE,
+ according to the actual parameter data type.
+
+ 2. In the "value" member.
+ It's initialized in:
+ - Item_param::set_param_func(), for client-server PS protocol.
+ - Item_param::set_from_item(), for EXECUTE and EXECUTE IMMEDIATE.
*/
class Item_param :public Item_basic_value,
private Settable_routine_parameter,
public Rewritable_query_parameter,
- public Type_handler_hybrid_field_type,
+ private Type_handler_hybrid_field_type,
public Type_geometry_attributes
{
/*
@@ -3113,9 +3144,8 @@ class Item_param :public Item_basic_value,
*/
enum enum_item_param_state
{
- NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE,
- STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE,
- DECIMAL_VALUE, DEFAULT_VALUE, IGNORE_VALUE
+ NO_VALUE, NULL_VALUE, SHORT_DATA_VALUE, LONG_DATA_VALUE,
+ DEFAULT_VALUE, IGNORE_VALUE
} state;
enum Type item_type;
@@ -3128,7 +3158,6 @@ class Item_param :public Item_basic_value,
void fix_temporal(uint32 max_length_arg, uint decimals_arg);
-public:
struct CONVERSION_INFO
{
/*
@@ -3170,31 +3199,71 @@ public:
}
};
+ bool m_empty_string_is_null;
+
+ class PValue_simple
+ {
+ public:
+ union
+ {
+ longlong integer;
+ double real;
+ CONVERSION_INFO cs_info;
+ MYSQL_TIME time;
+ };
+ void swap(PValue_simple &other)
+ {
+ swap_variables(PValue_simple, *this, other);
+ }
+ };
+
+ class PValue: public Type_handler_hybrid_field_type,
+ public PValue_simple,
+ public Value_source
+ {
+ public:
+ PValue(): Type_handler_hybrid_field_type(&type_handler_null) {}
+ my_decimal m_decimal;
+ String m_string;
+ /*
+ A buffer for string and long data values. Historically all allocated
+ values returned from val_str() were treated as eligible to
+ modification. I. e. in some cases Item_func_concat can append it's
+ second argument to return value of the first one. Because of that we
+ can't return the original buffer holding string data from val_str(),
+ and have to have one buffer for data and another just pointing to
+ the data. This is the latter one and it's returned from val_str().
+ Can not be declared inside the union as it's not a POD type.
+ */
+ String m_string_ptr;
+
+ void swap(PValue &other)
+ {
+ Type_handler_hybrid_field_type::swap(other);
+ PValue_simple::swap(other);
+ m_decimal.swap(other.m_decimal);
+ m_string.swap(other.m_string);
+ m_string_ptr.swap(other.m_string_ptr);
+ }
+ double val_real() const;
+ longlong val_int(const Type_std_attributes *attr) const;
+ my_decimal *val_decimal(my_decimal *dec, const Type_std_attributes *attr);
+ String *val_str(String *str, const Type_std_attributes *attr);
+ };
+
+ PValue value;
+
+ const String *value_query_val_str(THD *thd, String* str) const;
+ bool value_eq(const Item *item, bool binary_cmp) const;
+ Item *value_clone_item(THD *thd);
+ bool can_return_value() const;
+
+public:
/*
Used for bulk protocol only.
*/
enum enum_indicator_type indicator;
- /*
- A buffer for string and long data values. Historically all allocated
- values returned from val_str() were treated as eligible to
- modification. I. e. in some cases Item_func_concat can append it's
- second argument to return value of the first one. Because of that we
- can't return the original buffer holding string data from val_str(),
- and have to have one buffer for data and another just pointing to
- the data. This is the latter one and it's returned from val_str().
- Can not be declared inside the union as it's not a POD type.
- */
- String str_value_ptr;
- my_decimal decimal_value;
- union
- {
- longlong integer;
- double real;
- CONVERSION_INFO cs_info;
- MYSQL_TIME time;
- } value;
-
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
@@ -3213,10 +3282,22 @@ public:
return item_type;
}
- double val_real();
- longlong val_int();
- my_decimal *val_decimal(my_decimal*);
- String *val_str(String*);
+ double val_real()
+ {
+ return can_return_value() ? value.val_real() : 0e0;
+ }
+ longlong val_int()
+ {
+ return can_return_value() ? value.val_int(this) : 0;
+ }
+ my_decimal *val_decimal(my_decimal *dec)
+ {
+ return can_return_value() ? value.val_decimal(dec, this) : NULL;
+ }
+ String *val_str(String *str)
+ {
+ return can_return_value() ? value.val_str(str, this) : NULL;
+ }
bool get_date(MYSQL_TIME *tm, ulonglong fuzzydate);
int save_in_field(Field *field, bool no_conversions);
@@ -3227,20 +3308,64 @@ public:
void set_double(double i);
void set_decimal(const char *str, ulong length);
void set_decimal(const my_decimal *dv, bool unsigned_arg);
- bool set_str(const char *str, ulong length);
+ bool set_str(const char *str, ulong length,
+ CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
bool set_longdata(const char *str, ulong length);
void set_time(MYSQL_TIME *tm, timestamp_type type, uint32 max_length_arg);
void set_time(const MYSQL_TIME *tm, uint32 max_length_arg, uint decimals_arg);
bool set_from_item(THD *thd, Item *item);
void reset();
+
+ void set_param_tiny(uchar **pos, ulong len);
+ void set_param_short(uchar **pos, ulong len);
+ void set_param_int32(uchar **pos, ulong len);
+ void set_param_int64(uchar **pos, ulong len);
+ void set_param_float(uchar **pos, ulong len);
+ void set_param_double(uchar **pos, ulong len);
+ void set_param_decimal(uchar **pos, ulong len);
+ void set_param_time(uchar **pos, ulong len);
+ void set_param_datetime(uchar **pos, ulong len);
+ void set_param_date(uchar **pos, ulong len);
+ void set_param_str(uchar **pos, ulong len);
+
+ void setup_conversion(THD *thd, uchar param_type);
+ void setup_conversion_blob(THD *thd);
+ void setup_conversion_string(THD *thd, CHARSET_INFO *fromcs);
+
/*
Assign placeholder value from bind data.
Note, that 'len' has different semantics in embedded library (as we
don't need to check that packet is not broken there). See
sql_prepare.cc for details.
*/
- void (*set_param_func)(Item_param *param, uchar **pos, ulong len);
+ void set_param_func(uchar **pos, ulong len)
+ {
+ /*
+ To avoid Item_param::set_xxx() asserting on data type mismatch,
+ we set the value type handler here:
+ - It can not be initialized yet after Item_param::setup_conversion().
+ - Also, for LIMIT clause parameters, the value type handler might have
+ changed from the real type handler to type_handler_longlong.
+ So here we'll restore it.
+ */
+ const Type_handler *h= Item_param::type_handler();
+ value.set_handler(h);
+ h->Item_param_set_param_func(this, pos, len);
+ }
+ bool set_value(THD *thd, const Type_all_attributes *attr,
+ const st_value *val, const Type_handler *h)
+ {
+ value.set_handler(h); // See comments in set_param_func()
+ return h->Item_param_set_from_value(thd, this, attr, val);
+ }
+
+ bool set_limit_clause_param(longlong nr)
+ {
+ value.set_handler(&type_handler_longlong);
+ set_int(nr, MY_INT64_NUM_DECIMAL_DIGITS);
+ return !unsigned_flag && value.integer < 0;
+ }
const String *query_val_str(THD *thd, String *str) const;
bool convert_str_value(THD *thd);
@@ -3266,7 +3391,8 @@ public:
}
bool has_int_value() const
{
- return state == INT_VALUE;
+ return state == SHORT_DATA_VALUE &&
+ value.type_handler()->cmp_type() == INT_RESULT;
}
/*
This method is used to make a copy of a basic constant item when
@@ -3307,6 +3433,8 @@ private:
public:
virtual const Send_field *get_out_param_info() const;
+ Item_param *get_item_param() { return this; }
+
virtual void make_field(THD *thd, Send_field *field);
private:
@@ -3519,7 +3647,7 @@ class Item_string :public Item_basic_constant
protected:
void fix_from_value(Derivation dv, const Metadata metadata)
{
- fix_charset_and_length_from_str_value(dv, metadata);
+ fix_charset_and_length(str_value.charset(), dv, metadata);
// it is constant => can be used without fix_fields (and frequently used)
fixed= 1;
}
@@ -4229,7 +4357,8 @@ public:
*/
class Item_func_or_sum: public Item_result_field,
public Item_args,
- public Used_tables_and_const_cache
+ public Used_tables_and_const_cache,
+ public With_subquery_cache
{
protected:
bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems,
@@ -4312,6 +4441,7 @@ public:
Used_tables_and_const_cache(item) { }
Item_func_or_sum(THD *thd, List<Item> &list):
Item_result_field(thd), Item_args(thd, list) { }
+ bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; }
bool walk(Item_processor processor, bool walk_subquery, void *arg)
{
if (walk_args(processor, walk_subquery, arg))
@@ -4526,9 +4656,9 @@ public:
/**
Checks if the item tree that ref points to contains a subquery.
*/
- virtual bool has_subquery() const
- {
- return (*ref)->has_subquery();
+ virtual bool with_subquery() const
+ {
+ return (*ref)->with_subquery();
}
Item *get_copy(THD *thd)
{ return get_item_copy<Item_ref>(thd, this); }
@@ -4645,7 +4775,8 @@ class Expression_cache_tracker;
The objects of this class can store its values in an expression cache.
*/
-class Item_cache_wrapper :public Item_result_field
+class Item_cache_wrapper :public Item_result_field,
+ public With_subquery_cache
{
private:
/* Pointer on the cached expression */
@@ -4672,6 +4803,7 @@ public:
enum Type type() const { return EXPR_CACHE_ITEM; }
enum Type real_type() const { return orig_item->type(); }
+ bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; }
bool set_cache(THD *thd);
Expression_cache_tracker* init_tracker(MEM_ROOT *mem_root);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index fed7243a8c2..191616365fd 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1365,7 +1365,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
}
if (args[1]->maybe_null)
maybe_null=1;
- with_subselect= 1;
+ m_with_subquery= true;
with_sum_func= with_sum_func || args[1]->with_sum_func;
with_field= with_field || args[1]->with_field;
used_tables_and_const_cache_join(args[1]);
@@ -4623,7 +4623,7 @@ Item_cond::fix_fields(THD *thd, Item **ref)
with_sum_func|= item->with_sum_func;
with_field|= item->with_field;
- with_subselect|= item->has_subquery();
+ m_with_subquery|= item->with_subquery();
with_window_func|= item->with_window_func;
maybe_null|= item->maybe_null;
}
@@ -5485,7 +5485,7 @@ void Regexp_processor_pcre::pcre_exec_warn(int rc) const
switch (rc)
{
case PCRE_ERROR_NULL:
- errmsg= "pcre_exec: null arguement passed";
+ errmsg= "pcre_exec: null argument passed";
break;
case PCRE_ERROR_BADOPTION:
errmsg= "pcre_exec: bad option";
@@ -6627,7 +6627,7 @@ bool Item_equal::fix_fields(THD *thd, Item **ref)
used_tables_cache|= item->used_tables();
tmp_table_map= item->not_null_tables();
not_null_tables_cache|= tmp_table_map;
- DBUG_ASSERT(!item->with_sum_func && !item->with_subselect);
+ DBUG_ASSERT(!item->with_sum_func && !item->with_subquery());
if (item->maybe_null)
maybe_null= 1;
if (!item->get_item_equal())
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 0a3339e7ffe..1561a78a12a 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -356,7 +356,7 @@ public:
Item_in_optimizer(THD *thd, Item *a, Item *b):
Item_bool_func(thd, a, b), cache(0), expr_cache(0),
save_cache(0), result_for_null_param(UNKNOWN)
- { with_subselect= true; }
+ { m_with_subquery= true; }
bool fix_fields(THD *, Item **);
bool fix_left(THD *thd);
table_map not_null_tables() const { return 0; }
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 659ec29e452..67269e4dd0e 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -362,7 +362,7 @@ Item_func::fix_fields(THD *thd, Item **ref)
with_window_func= with_window_func || item->with_window_func;
with_field= with_field || item->with_field;
used_tables_and_const_cache_join(item);
- with_subselect|= item->has_subquery();
+ m_with_subquery|= item->with_subquery();
}
}
if (check_arguments())
@@ -3249,7 +3249,7 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func,
func->maybe_null=1;
func->with_sum_func= func->with_sum_func || item->with_sum_func;
func->with_field= func->with_field || item->with_field;
- func->with_subselect|= item->with_subselect;
+ func->With_subquery_cache::join(item);
func->used_tables_and_const_cache_join(item);
f_args.arg_type[i]=item->result_type();
}
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index a060ed221bf..aee44a7a01f 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -165,6 +165,9 @@ String *Item_func_geometry_from_json::val_str(String *str)
case Geometry::GEOJ_TOO_FEW_POINTS:
code= ER_GEOJSON_TOO_FEW_POINTS;
break;
+ case Geometry::GEOJ_EMPTY_COORDINATES:
+ code= ER_GEOJSON_EMPTY_COORDINATES;
+ break;
case Geometry::GEOJ_POLYGON_NOT_CLOSED:
code= ER_GEOJSON_NOT_CLOSED;
break;
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index 54ffa5a2e63..7afb94ba332 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -69,6 +69,7 @@ static inline bool append_simple(String *s, const uchar *a, size_t a_len)
/*
Appends JSON string to the String object taking charsets in
consideration.
+*/
static int st_append_json(String *s,
CHARSET_INFO *json_cs, const uchar *js, uint js_len)
{
@@ -82,9 +83,8 @@ static int st_append_json(String *s,
return 0;
}
- return js_len;
+ return str_len;
}
-*/
/*
@@ -475,6 +475,9 @@ String *Item_func_json_value::val_str(String *str)
json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
(const uchar *) js->ptr() + js->length());
+ str->length(0);
+ str->set_charset(&my_charset_utf8mb4_bin);
+
path.cur_step= path.p.steps;
continue_search:
if (json_find_path(&je, &path.p, &path.cur_step, array_counters))
@@ -515,8 +518,7 @@ bool Item_func_json_value::check_and_get_value(json_engine_t *je, String *res,
return true;
}
- res->set((const char *) je->value, je->value_len, je->s.cs);
- return false;
+ return st_append_json(res, je->s.cs, je->value, je->value_len);
}
diff --git a/sql/item_row.cc b/sql/item_row.cc
index eae88cd2e6e..64794093bec 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -64,7 +64,7 @@ bool Item_row::fix_fields(THD *thd, Item **ref)
with_sum_func= with_sum_func || item->with_sum_func;
with_window_func = with_window_func || item->with_window_func;
with_field= with_field || item->with_field;
- with_subselect|= item->with_subselect;
+ m_with_subquery|= item->with_subquery();
}
fixed= 1;
return FALSE;
diff --git a/sql/item_row.h b/sql/item_row.h
index a66ae7fb5dc..064c1f267b4 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -35,7 +35,8 @@
*/
class Item_row: public Item,
private Item_args,
- private Used_tables_and_const_cache
+ private Used_tables_and_const_cache,
+ private With_subquery_cache
{
table_map not_null_tables_cache;
/**
@@ -52,6 +53,7 @@ public:
not_null_tables_cache(0), with_null(0)
{ }
+ bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; }
enum Type type() const { return ROW_ITEM; };
const Type_handler *type_handler() const { return &type_handler_row; }
void illegal_method_call(const char *);
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 3a7d8582913..e47fa17896d 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -64,7 +64,6 @@ Item_subselect::Item_subselect(THD *thd_arg):
#ifndef DBUG_OFF
exec_counter= 0;
#endif
- with_subselect= 1;
reset();
/*
Item value is NULL if select_result_interceptor didn't change this value
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index e48b45fb11e..55c9d759ddf 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -182,6 +182,7 @@ public:
return null_value;
}
bool fix_fields(THD *thd, Item **ref);
+ bool with_subquery() const { DBUG_ASSERT(fixed); return true; }
bool mark_as_dependent(THD *thd, st_select_lex *select, Item *item);
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
void recalc_used_tables(st_select_lex *new_parent, bool after_pullout);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 269190ef3df..8c624b3684a 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1126,7 +1126,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref)
if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1))
return TRUE;
set_if_bigger(decimals, args[i]->decimals);
- with_subselect|= args[i]->with_subselect;
+ m_with_subquery|= args[i]->with_subquery();
with_window_func|= args[i]->with_window_func;
}
result_field=0;
@@ -1157,7 +1157,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
if ((!item->fixed && item->fix_fields(thd, args)) ||
(item= args[0])->check_cols(1))
return TRUE;
- with_subselect= args[0]->with_subselect;
+ m_with_subquery= args[0]->with_subquery();
with_window_func|= args[0]->with_window_func;
fix_length_and_dec();
@@ -3447,7 +3447,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref)
args[i]->fix_fields(thd, args + i)) ||
args[i]->check_cols(1))
return TRUE;
- with_subselect|= args[i]->with_subselect;
+ m_with_subquery|= args[i]->with_subquery();
with_window_func|= args[i]->with_window_func;
}
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 3a7684fe7b4..fd170a707c9 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2434,6 +2434,8 @@ void Item_char_typecast::check_truncation_with_warn(String *src, uint dstlen)
THD *thd= current_thd;
char char_type[40];
ErrConvString err(src);
+ bool save_abort_on_warning= thd->abort_on_warning;
+ thd->abort_on_warning&= !m_suppress_warning_to_error_escalation;
my_snprintf(char_type, sizeof(char_type), "%s(%lu)",
cast_cs == &my_charset_bin ? "BINARY" : "CHAR",
(ulong) cast_length);
@@ -2441,6 +2443,7 @@ void Item_char_typecast::check_truncation_with_warn(String *src, uint dstlen)
ER_TRUNCATED_WRONG_VALUE,
ER_THD(thd, ER_TRUNCATED_WRONG_VALUE), char_type,
err.ptr());
+ thd->abort_on_warning= save_abort_on_warning;
}
}
@@ -2551,7 +2554,7 @@ void Item_char_typecast::fix_length_and_dec_numeric()
}
-void Item_char_typecast::fix_length_and_dec_str()
+void Item_char_typecast::fix_length_and_dec_generic()
{
fix_length_and_dec_internal(from_cs= args[0]->dynamic_result() ?
0 :
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index bf744cc24cd..adc7b2535a9 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -1089,6 +1089,7 @@ class Item_char_typecast :public Item_str_func
CHARSET_INFO *cast_cs, *from_cs;
bool charset_conversion;
String tmp_value;
+ bool m_suppress_warning_to_error_escalation;
bool has_explicit_length() const { return cast_length != ~0U; }
String *reuse(String *src, uint32 length);
String *copy(String *src, CHARSET_INFO *cs);
@@ -1097,14 +1098,20 @@ class Item_char_typecast :public Item_str_func
void fix_length_and_dec_internal(CHARSET_INFO *fromcs);
public:
Item_char_typecast(THD *thd, Item *a, uint length_arg, CHARSET_INFO *cs_arg):
- Item_str_func(thd, a), cast_length(length_arg), cast_cs(cs_arg) {}
+ Item_str_func(thd, a), cast_length(length_arg), cast_cs(cs_arg),
+ m_suppress_warning_to_error_escalation(false) {}
enum Functype functype() const { return CHAR_TYPECAST_FUNC; }
bool eq(const Item *item, bool binary_cmp) const;
const char *func_name() const { return "cast_as_char"; }
CHARSET_INFO *cast_charset() const { return cast_cs; }
String *val_str(String *a);
+ void fix_length_and_dec_generic();
void fix_length_and_dec_numeric();
- void fix_length_and_dec_str();
+ void fix_length_and_dec_str()
+ {
+ fix_length_and_dec_generic();
+ m_suppress_warning_to_error_escalation= true;
+ }
void fix_length_and_dec()
{
args[0]->type_handler()->Item_char_typecast_fix_length_and_dec(this);
diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc
index 8432ab43ad8..cd0fb5058a6 100644
--- a/sql/item_windowfunc.cc
+++ b/sql/item_windowfunc.cc
@@ -334,8 +334,8 @@ bool Item_sum_hybrid_simple::fix_fields(THD *thd, Item **ref)
return TRUE;
}
Type_std_attributes::set(args[0]);
- for (uint i= 0; i < arg_count && !with_subselect; i++)
- with_subselect= with_subselect || args[i]->with_subselect;
+ for (uint i= 0; i < arg_count && !m_with_subquery; i++)
+ m_with_subquery|= args[i]->with_subquery();
Item *item2= args[0]->real_item();
if (item2->type() == Item::FIELD_ITEM)
diff --git a/sql/lex.h b/sql/lex.h
index 63b0567c5d0..a0068069660 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -181,6 +181,7 @@ static SYMBOL symbols[] = {
{ "DELAYED", SYM(DELAYED_SYM)},
{ "DELAY_KEY_WRITE", SYM(DELAY_KEY_WRITE_SYM)},
{ "DELETE", SYM(DELETE_SYM)},
+ { "DELETE_DOMAIN_ID", SYM(DELETE_DOMAIN_ID_SYM)},
{ "DESC", SYM(DESC)},
{ "DESCRIBE", SYM(DESCRIBE)},
{ "DES_KEY_FILE", SYM(DES_KEY_FILE)},
diff --git a/sql/log.cc b/sql/log.cc
index 24da00844bc..704450aa547 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -6674,6 +6674,120 @@ void MYSQL_BIN_LOG::checkpoint_and_purge(ulong binlog_id)
purge();
}
+
+/**
+ Searches for the first (oldest) binlog file name in in the binlog index.
+
+ @param[in,out] buf_arg pointer to a buffer to hold found
+ the first binary log file name
+ @return NULL on success, otherwise error message
+*/
+static const char* get_first_binlog(char* buf_arg)
+{
+ IO_CACHE *index_file;
+ size_t length;
+ char fname[FN_REFLEN];
+ const char* errmsg= NULL;
+
+ DBUG_ENTER("get_first_binlog");
+
+ DBUG_ASSERT(mysql_bin_log.is_open());
+
+ mysql_bin_log.lock_index();
+
+ index_file=mysql_bin_log.get_index_file();
+ if (reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 0))
+ {
+ errmsg= "failed to create a cache on binlog index";
+ goto end;
+ }
+ /* The file ends with EOF or empty line */
+ if ((length=my_b_gets(index_file, fname, sizeof(fname))) <= 1)
+ {
+ errmsg= "empty binlog index";
+ goto end;
+ }
+ else
+ {
+ fname[length-1]= 0; // Remove end \n
+ }
+ if (normalize_binlog_name(buf_arg, fname, false))
+ {
+ errmsg= "cound not normalize the first file name in the binlog index";
+ goto end;
+ }
+end:
+ mysql_bin_log.unlock_index();
+
+ DBUG_RETURN(errmsg);
+}
+
+/**
+ Check weather the gtid binlog state can safely remove gtid
+ domains passed as the argument. A safety condition is satisfied when
+ there are no events from the being deleted domains in the currently existing
+ binlog files. Upon successful check the supplied domains are removed
+ from @@gtid_binlog_state. The caller is supposed to rotate binlog so that
+ the active latest file won't have the deleted domains in its Gtid_list header.
+
+ @param domain_drop_lex gtid domain id sequence from lex.
+ Passed as a pointer to dynamic array must be not empty
+ unless pointer value NULL.
+ @retval zero on success
+ @retval > 0 ineffective call none from the *non* empty
+ gtid domain sequence is deleted
+ @retval < 0 on error
+*/
+static int do_delete_gtid_domain(DYNAMIC_ARRAY *domain_drop_lex)
+{
+ int rc= 0;
+ Gtid_list_log_event *glev= NULL;
+ char buf[FN_REFLEN];
+ File file;
+ IO_CACHE cache;
+ const char* errmsg= NULL;
+ char errbuf[MYSQL_ERRMSG_SIZE]= {0};
+
+ if (!domain_drop_lex)
+ return 0; // still "effective" having empty domain sequence to delete
+
+ DBUG_ASSERT(domain_drop_lex->elements > 0);
+ mysql_mutex_assert_owner(mysql_bin_log.get_log_lock());
+
+ if ((errmsg= get_first_binlog(buf)) != NULL)
+ goto end;
+ bzero((char*) &cache, sizeof(cache));
+ if ((file= open_binlog(&cache, buf, &errmsg)) == (File) -1)
+ goto end;
+ errmsg= get_gtid_list_event(&cache, &glev);
+ end_io_cache(&cache);
+ mysql_file_close(file, MYF(MY_WME));
+
+ DBUG_EXECUTE_IF("inject_binlog_delete_domain_init_error",
+ errmsg= "injected error";);
+ if (errmsg)
+ goto end;
+ errmsg= rpl_global_gtid_binlog_state.drop_domain(domain_drop_lex,
+ glev, errbuf);
+
+end:
+ if (errmsg)
+ {
+ if (strlen(errmsg) > 0)
+ {
+ my_error(ER_BINLOG_CANT_DELETE_GTID_DOMAIN, MYF(0), errmsg);
+ rc= -1;
+ }
+ else
+ {
+ rc= 1;
+ }
+ }
+ delete glev;
+
+ return rc;
+}
+
/**
The method is a shortcut of @c rotate() and @c purge().
LOCK_log is acquired prior to rotate and is released after it.
@@ -6683,16 +6797,24 @@ void MYSQL_BIN_LOG::checkpoint_and_purge(ulong binlog_id)
@retval
nonzero - error in rotating routine.
*/
-int MYSQL_BIN_LOG::rotate_and_purge(bool force_rotate)
+int MYSQL_BIN_LOG::rotate_and_purge(bool force_rotate,
+ DYNAMIC_ARRAY *domain_drop_lex)
{
- int error= 0;
+ int err_gtid=0, error= 0;
ulong prev_binlog_id;
DBUG_ENTER("MYSQL_BIN_LOG::rotate_and_purge");
bool check_purge= false;
mysql_mutex_lock(&LOCK_log);
prev_binlog_id= current_binlog_id;
- if ((error= rotate(force_rotate, &check_purge)))
+
+ if ((err_gtid= do_delete_gtid_domain(domain_drop_lex)))
+ {
+ // inffective attempt to delete merely skips rotate and purge
+ if (err_gtid < 0)
+ error= 1; // otherwise error is propagated the user
+ }
+ else if ((error= rotate(force_rotate, &check_purge)))
check_purge= false;
/*
NOTE: Run purge_logs wo/ holding LOCK_log because it does not need
@@ -7096,8 +7218,15 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd,
mode. Also, do not write the cached updates to binlog if binary logging is
disabled (log-bin/sql_log_bin).
*/
- if (wsrep_emulate_bin_log || !(thd->variables.option_bits & OPTION_BIN_LOG))
+ if (wsrep_emulate_bin_log)
+ {
DBUG_RETURN(0);
+ }
+ else if (!(thd->variables.option_bits & OPTION_BIN_LOG))
+ {
+ cache_mngr->need_unlog= false;
+ DBUG_RETURN(0);
+ }
entry.thd= thd;
entry.cache_mngr= cache_mngr;
@@ -9398,11 +9527,19 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all,
if (err)
DBUG_RETURN(0);
+
+ bool need_unlog= cache_mngr->need_unlog;
+ /*
+ The transaction won't need the flag anymore.
+ Todo/fixme: consider to move the statement into cache_mngr->reset()
+ relocated to the current or later point.
+ */
+ cache_mngr->need_unlog= false;
/*
If using explicit user XA, we will not have XID. We must still return a
non-zero cookie (as zero cookie signals error).
*/
- if (!xid || !cache_mngr->need_unlog)
+ if (!xid || !need_unlog)
DBUG_RETURN(BINLOG_COOKIE_DUMMY(cache_mngr->delayed_error));
else
DBUG_RETURN(BINLOG_COOKIE_MAKE(cache_mngr->binlog_id,
@@ -9475,6 +9612,9 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint)
if (b->binlog_id == binlog_id)
{
--b->xid_count;
+
+ DBUG_ASSERT(b->xid_count >= 0); // catch unmatched (++) decrement
+
break;
}
first= false;
@@ -10248,6 +10388,73 @@ TC_LOG_BINLOG::set_status_variables(THD *thd)
}
}
+
+/*
+ Find the Gtid_list_log_event at the start of a binlog.
+
+ NULL for ok, non-NULL error message for error.
+
+ If ok, then the event is returned in *out_gtid_list. This can be NULL if we
+ get back to binlogs written by old server version without GTID support. If
+ so, it means we have reached the point to start from, as no GTID events can
+ exist in earlier binlogs.
+*/
+const char *
+get_gtid_list_event(IO_CACHE *cache, Gtid_list_log_event **out_gtid_list)
+{
+ Format_description_log_event init_fdle(BINLOG_VERSION);
+ Format_description_log_event *fdle;
+ Log_event *ev;
+ const char *errormsg = NULL;
+
+ *out_gtid_list= NULL;
+
+ if (!(ev= Log_event::read_log_event(cache, 0, &init_fdle,
+ opt_master_verify_checksum)) ||
+ ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
+ {
+ if (ev)
+ delete ev;
+ return "Could not read format description log event while looking for "
+ "GTID position in binlog";
+ }
+
+ fdle= static_cast<Format_description_log_event *>(ev);
+
+ for (;;)
+ {
+ Log_event_type typ;
+
+ ev= Log_event::read_log_event(cache, 0, fdle, opt_master_verify_checksum);
+ if (!ev)
+ {
+ errormsg= "Could not read GTID list event while looking for GTID "
+ "position in binlog";
+ break;
+ }
+ typ= ev->get_type_code();
+ if (typ == GTID_LIST_EVENT)
+ break; /* Done, found it */
+ if (typ == START_ENCRYPTION_EVENT)
+ {
+ if (fdle->start_decryption((Start_encryption_log_event*) ev))
+ errormsg= "Could not set up decryption for binlog.";
+ }
+ delete ev;
+ if (typ == ROTATE_EVENT || typ == STOP_EVENT ||
+ typ == FORMAT_DESCRIPTION_EVENT || typ == START_ENCRYPTION_EVENT)
+ continue; /* Continue looking */
+
+ /* We did not find any Gtid_list_log_event, must be old binlog. */
+ ev= NULL;
+ break;
+ }
+
+ delete fdle;
+ *out_gtid_list= static_cast<Gtid_list_log_event *>(ev);
+ return errormsg;
+}
+
struct st_mysql_storage_engine binlog_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
diff --git a/sql/log.h b/sql/log.h
index 30829bdb33c..dffb6a80d54 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -759,7 +759,7 @@ public:
int update_log_index(LOG_INFO* linfo, bool need_update_threads);
int rotate(bool force_rotate, bool* check_purge);
void checkpoint_and_purge(ulong binlog_id);
- int rotate_and_purge(bool force_rotate);
+ int rotate_and_purge(bool force_rotate, DYNAMIC_ARRAY* drop_gtid_domain= NULL);
/**
Flush binlog cache and synchronize to disk.
@@ -1169,4 +1169,9 @@ static inline TC_LOG *get_tc_log_implementation()
return &tc_log_mmap;
}
+
+class Gtid_list_log_event;
+const char *
+get_gtid_list_event(IO_CACHE *cache, Gtid_list_log_event **out_gtid_list);
+
#endif /* LOG_H */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index fd794bfe02b..439a8b34047 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -5942,9 +5942,6 @@ int mysqld_main(int argc, char **argv)
#ifdef __WIN__
if (!opt_console)
{
- if (reopen_fstreams(log_error_file, stdout, stderr))
- unireg_abort(1);
- setbuf(stderr, NULL);
FreeConsole(); // Remove window
}
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 72da68816ad..9cd2eedb55d 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -1631,7 +1631,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
// The subqueries were replaced for Item_int(1) earlier
subq_pred->reset_strategy(SUBS_SEMI_JOIN); // for subsequent executions
- /*TODO: also reset the 'with_subselect' there. */
+ /*TODO: also reset the 'm_with_subquery' there. */
/* n. Adjust the parent_join->table_count counter */
uint table_no= parent_join->table_count;
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 6fdbdfce893..0dc9a2638eb 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -42,13 +42,12 @@ partition_info *partition_info::get_clone(THD *thd)
List_iterator<partition_element> part_it(partitions);
partition_element *part;
- partition_info *clone= new (mem_root) partition_info();
+ partition_info *clone= new (mem_root) partition_info(*this);
if (!clone)
{
mem_alloc_error(sizeof(partition_info));
DBUG_RETURN(NULL);
}
- memcpy(clone, this, sizeof(partition_info));
memset(&(clone->read_partitions), 0, sizeof(clone->read_partitions));
memset(&(clone->lock_partitions), 0, sizeof(clone->lock_partitions));
clone->bitmaps_are_initialized= FALSE;
diff --git a/sql/protocol.cc b/sql/protocol.cc
index dbaa8ae6a1e..fae399e66e2 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -1327,6 +1327,7 @@ bool Protocol_text::send_out_parameters(List<Item_param> *sp_params)
continue;
}
+ DBUG_ASSERT(sparam->get_item_param() == NULL);
sparam->set_value(thd, thd->spcont, reinterpret_cast<Item **>(&item_param));
}
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index d58a2ea4d3e..369b072ab47 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -26,7 +26,7 @@
#include "rpl_gtid.h"
#include "rpl_rli.h"
#include "slave.h"
-
+#include "log_event.h"
const LEX_STRING rpl_gtid_slave_state_table_name=
{ C_STRING_WITH_LEN("gtid_slave_pos") };
@@ -1940,6 +1940,155 @@ end:
return res;
}
+/**
+ Remove domains supplied by the first argument from binlog state.
+ Removal is done for any domain whose last gtids (from all its servers) match
+ ones in Gtid list event of the 2nd argument.
+
+ @param ids gtid domain id sequence, may contain dups
+ @param glev pointer to Gtid list event describing
+ the match condition
+ @param errbuf [out] pointer to possible error message array
+
+ @retval NULL as success when at least one domain is removed
+ @retval "" empty string to indicate ineffective call
+ when no domains removed
+ @retval NOT EMPTY string otherwise an error message
+*/
+const char*
+rpl_binlog_state::drop_domain(DYNAMIC_ARRAY *ids,
+ Gtid_list_log_event *glev,
+ char* errbuf)
+{
+ DYNAMIC_ARRAY domain_unique; // sequece (unsorted) of unique element*:s
+ rpl_binlog_state::element* domain_unique_buffer[16];
+ ulong k, l;
+ const char* errmsg= NULL;
+
+ DBUG_ENTER("rpl_binlog_state::drop_domain");
+
+ my_init_dynamic_array2(&domain_unique,
+ sizeof(element*), domain_unique_buffer,
+ sizeof(domain_unique_buffer) / sizeof(element*), 4, 0);
+
+ mysql_mutex_lock(&LOCK_binlog_state);
+
+ /*
+ Gtid list is supposed to come from a binlog's Gtid_list event and
+ therefore should be a subset of the current binlog state. That is
+ for every domain in the list the binlog state contains a gtid with
+ sequence number not less than that of the list.
+ Exceptions of this inclusion rule are:
+ A. the list may still refer to gtids from already deleted domains.
+ Files containing them must have been purged whereas the file
+ with the list is not yet.
+ B. out of order groups were injected
+ C. manually build list of binlog files violating the inclusion
+ constraint.
+ While A is a normal case (not necessarily distinguishable from C though),
+ B and C may require the user's attention so any (incl the A's suspected)
+ inconsistency is diagnosed and *warned*.
+ */
+ for (l= 0, errbuf[0]= 0; l < glev->count; l++, errbuf[0]= 0)
+ {
+ rpl_gtid* rb_state_gtid= find_nolock(glev->list[l].domain_id,
+ glev->list[l].server_id);
+ if (!rb_state_gtid)
+ sprintf(errbuf,
+ "missing gtids from the '%u-%u' domain-server pair which is "
+ "referred to in the gtid list describing an earlier state. Ignore "
+ "if the domain ('%u') was already explicitly deleted",
+ glev->list[l].domain_id, glev->list[l].server_id,
+ glev->list[l].domain_id);
+ else if (rb_state_gtid->seq_no < glev->list[l].seq_no)
+ sprintf(errbuf,
+ "having a gtid '%u-%u-%llu' which is less than "
+ "the '%u-%u-%llu' of the gtid list describing an earlier state. "
+ "The state may have been affected by manually injecting "
+ "a lower sequence number gtid or via replication",
+ rb_state_gtid->domain_id, rb_state_gtid->server_id,
+ rb_state_gtid->seq_no, glev->list[l].domain_id,
+ glev->list[l].server_id, glev->list[l].seq_no);
+ if (strlen(errbuf)) // use strlen() as cheap flag
+ push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_BINLOG_CANT_DELETE_GTID_DOMAIN,
+ "The current gtid binlog state is incompatible with "
+ "a former one %s.", errbuf);
+ }
+
+ /*
+ For each domain_id from ids
+ when no such domain in binlog state
+ warn && continue
+ For each domain.server's last gtid
+ when not locate the last gtid in glev.list
+ error out binlog state can't change
+ otherwise continue
+ */
+ for (ulong i= 0; i < ids->elements; i++)
+ {
+ rpl_binlog_state::element *elem= NULL;
+ ulong *ptr_domain_id;
+ bool not_match;
+
+ ptr_domain_id= (ulong*) dynamic_array_ptr(ids, i);
+ elem= (rpl_binlog_state::element *)
+ my_hash_search(&hash, (const uchar *) ptr_domain_id, 0);
+ if (!elem)
+ {
+ push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_BINLOG_CANT_DELETE_GTID_DOMAIN,
+ "The gtid domain being deleted ('%lu') is not in "
+ "the current binlog state", *ptr_domain_id);
+ continue;
+ }
+
+ for (not_match= true, k= 0; k < elem->hash.records; k++)
+ {
+ rpl_gtid *d_gtid= (rpl_gtid *)my_hash_element(&elem->hash, k);
+ for (ulong l= 0; l < glev->count && not_match; l++)
+ not_match= !(*d_gtid == glev->list[l]);
+ }
+
+ if (not_match)
+ {
+ sprintf(errbuf, "binlog files may contain gtids from the domain ('%lu') "
+ "being deleted. Make sure to first purge those files",
+ *ptr_domain_id);
+ errmsg= errbuf;
+ goto end;
+ }
+ // compose a sequence of unique pointers to domain object
+ for (k= 0; k < domain_unique.elements; k++)
+ {
+ if ((rpl_binlog_state::element*) dynamic_array_ptr(&domain_unique, k)
+ == elem)
+ break; // domain_id's elem has been already in
+ }
+ if (k == domain_unique.elements) // proven not to have duplicates
+ insert_dynamic(&domain_unique, (uchar*) &elem);
+ }
+
+ // Domain removal from binlog state
+ for (k= 0; k < domain_unique.elements; k++)
+ {
+ rpl_binlog_state::element *elem= *(rpl_binlog_state::element**)
+ dynamic_array_ptr(&domain_unique, k);
+ my_hash_free(&elem->hash);
+ my_hash_delete(&hash, (uchar*) elem);
+ }
+
+ DBUG_ASSERT(strlen(errbuf) == 0);
+
+ if (domain_unique.elements == 0)
+ errmsg= "";
+
+end:
+ mysql_mutex_unlock(&LOCK_binlog_state);
+ delete_dynamic(&domain_unique);
+
+ DBUG_RETURN(errmsg);
+}
slave_connection_state::slave_connection_state()
{
diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h
index c473ff40ee9..d30bfa64b87 100644
--- a/sql/rpl_gtid.h
+++ b/sql/rpl_gtid.h
@@ -34,6 +34,13 @@ struct rpl_gtid
uint64 seq_no;
};
+inline bool operator==(const rpl_gtid& lhs, const rpl_gtid& rhs)
+{
+ return
+ lhs.domain_id == rhs.domain_id &&
+ lhs.server_id == rhs.server_id &&
+ lhs.seq_no == rhs.seq_no;
+};
enum enum_gtid_skip_type {
GTID_SKIP_NOT, GTID_SKIP_STANDALONE, GTID_SKIP_TRANSACTION
@@ -93,6 +100,7 @@ struct gtid_waiting {
class Relay_log_info;
struct rpl_group_info;
+class Gtid_list_log_event;
/*
Replication slave state.
@@ -315,6 +323,7 @@ struct rpl_binlog_state
rpl_gtid *find_nolock(uint32 domain_id, uint32 server_id);
rpl_gtid *find(uint32 domain_id, uint32 server_id);
rpl_gtid *find_most_recent(uint32 domain_id);
+ const char* drop_domain(DYNAMIC_ARRAY *ids, Gtid_list_log_event *glev, char*);
};
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index e7afe7a679a..20610117d14 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -1801,8 +1801,8 @@ ER_WRONG_AUTO_KEY 42000 S1009
spa "Puede ser solamente un campo automatico y este debe ser definido como una clave"
swe "Det får finnas endast ett AUTO_INCREMENT-fält och detta måste vara en nyckel"
ukr "Невірне визначення таблиці; Може бути лише один автоматичний стовбець, що повинен бути визначений як ключ"
-ER_UNUSED_9
- eng "You should never see it"
+ER_BINLOG_CANT_DELETE_GTID_DOMAIN
+ eng "Could not delete gtid domain. Reason: %s."
ER_NORMAL_SHUTDOWN
cze "%s (%s): normální ukončení\n"
dan "%s (%s): Normal nedlukning\n"
@@ -7330,7 +7330,7 @@ ER_SUBQUERIES_NOT_SUPPORTED 42000
eng "%s does not support subqueries or stored functions"
ER_SET_STATEMENT_NOT_SUPPORTED 42000
eng "The system variable %.200s cannot be set in SET STATEMENT."
-ER_UNUSED_17
+ER_UNUSED_9
eng "You should never see it"
ER_USER_CREATE_EXISTS
eng "Can't create user '%-.64s'@'%-.64s'; it already exists"
@@ -7747,6 +7747,9 @@ ER_SUM_FUNC_WITH_WINDOW_FUNC_AS_ARG
ER_NET_OK_PACKET_TOO_LARGE
eng "OK packet too large"
+ER_GEOJSON_EMPTY_COORDINATES
+ eng "Incorrect GeoJSON format - empty 'coordinates' array."
+
ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
eng "Illegal parameter data types %s and %s for operation '%s'"
ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index f402b4919b9..829e4cc6414 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1022,6 +1022,19 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
if (check_stack_overrun(thd, 7 * STACK_MIN_SIZE, (uchar*)&old_packet))
DBUG_RETURN(TRUE);
+ /*
+ Normally the counter is not reset between parsing and first execution,
+ but it is possible in case of error to have parsing on one CALL and
+ first execution (where VIEW will be parsed and added). So we store the
+ counter after parsing and restore it before execution just to avoid
+ repeating SELECT numbers.
+
+ Other problem is that it can be more SELECTs parsed in case of fixing
+ error causes previous interruption of the SP. So it is save not just
+ assign old value but add it.
+ */
+ thd->select_number+= m_select_number;
+
/* init per-instruction memroot */
init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
@@ -1361,6 +1374,16 @@ 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);
}
@@ -2065,26 +2088,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (!err_status)
{
- /*
- 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.
- */
- thd->select_number= m_select_number;
-
err_status= execute(thd, TRUE);
- DBUG_PRINT("info", ("execute returned %d", (int) err_status));
- /*
- 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);
}
if (save_log_general)
@@ -4177,7 +4181,7 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp)
Query_arena backup_arena;
DBUG_ENTER("sp_instr_cfetch::execute");
- res= c ? c->fetch(thd, &m_varlist) : -1;
+ res= c ? c->fetch(thd, &m_varlist, m_error_on_no_data) : -1;
*nextp= m_ip+1;
DBUG_RETURN(res);
@@ -4777,7 +4781,7 @@ bool sp_head::add_for_loop_open_cursor(THD *thd, sp_pcontext *spcont,
sp_instr_cfetch *instr_cfetch=
new (thd->mem_root) sp_instr_cfetch(instructions(),
- spcont, coffset);
+ spcont, coffset, false);
if (instr_cfetch == NULL || add_instr(instr_cfetch))
return true;
instr_cfetch->add_to_varlist(index);
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 734c0dea3e3..8d836732a10 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -1795,8 +1795,8 @@ class sp_instr_cfetch : public sp_instr
public:
- sp_instr_cfetch(uint ip, sp_pcontext *ctx, uint c)
- : sp_instr(ip, ctx), m_cursor(c)
+ sp_instr_cfetch(uint ip, sp_pcontext *ctx, uint c, bool error_on_no_data)
+ : sp_instr(ip, ctx), m_cursor(c), m_error_on_no_data(error_on_no_data)
{
m_varlist.empty();
}
@@ -1817,6 +1817,7 @@ private:
uint m_cursor;
List<sp_variable> m_varlist;
+ bool m_error_on_no_data;
}; // class sp_instr_cfetch : public sp_instr
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 6716aa54170..b6f9e733af1 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -800,7 +800,13 @@ int sp_cursor::open_view_structure_only(THD *thd)
if (!(thd->lex->limit_rows_examined= new (thd->mem_root) Item_uint(thd, 0)))
return -1;
thd->no_errors= true; // Suppress ER_QUERY_EXCEEDED_ROWS_EXAMINED_LIMIT
+ DBUG_ASSERT(!thd->killed);
res= open(thd);
+ /*
+ The query possibly exited on LIMIT ROWS EXAMINED and set thd->killed.
+ Reset it now.
+ */
+ thd->reset_killed();
thd->no_errors= thd_no_errors_save;
thd->lex->limit_rows_examined= limit_rows_examined;
return res;
@@ -829,7 +835,7 @@ void sp_cursor::destroy()
}
-int sp_cursor::fetch(THD *thd, List<sp_variable> *vars)
+int sp_cursor::fetch(THD *thd, List<sp_variable> *vars, bool error_on_no_data)
{
if (! server_side_cursor)
{
@@ -866,7 +872,7 @@ int sp_cursor::fetch(THD *thd, List<sp_variable> *vars)
if (! server_side_cursor->is_open())
{
m_found= false;
- if (thd->variables.sql_mode & MODE_ORACLE)
+ if (!error_on_no_data)
return 0;
my_message(ER_SP_FETCH_NO_DATA, ER_THD(thd, ER_SP_FETCH_NO_DATA), MYF(0));
return -1;
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 658972ece40..9b70b1d4c6b 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -455,7 +455,7 @@ public:
ulonglong fetch_count() const
{ return m_fetch_count; }
- int fetch(THD *, List<sp_variable> *vars);
+ int fetch(THD *, List<sp_variable> *vars, bool error_on_no_data);
bool export_structure(THD *thd, Row_definition_list *list);
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 19035a4e882..2a07ef2ecbe 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -1041,7 +1041,7 @@ bool Gis_line_string::init_from_json(json_engine_t *je, bool er_on_3D,
}
if (n_points < 1)
{
- je->s.error= GEOJ_TOO_FEW_POINTS;
+ je->s.error= Geometry::GEOJ_TOO_FEW_POINTS;
return TRUE;
}
wkb->write_at_position(np_pos, n_points);
@@ -1440,6 +1440,15 @@ bool Gis_polygon::init_from_json(json_engine_t *je, bool er_on_3D, String *wkb)
}
n_linear_rings++;
}
+
+ if (je->s.error)
+ return TRUE;
+
+ if (n_linear_rings == 0)
+ {
+ je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
+ return TRUE;
+ }
wkb->write_at_position(lr_pos, n_linear_rings);
return FALSE;
}
@@ -1945,6 +1954,14 @@ bool Gis_multi_point::init_from_json(json_engine_t *je, bool er_on_3D,
n_points++;
}
+ if (je->s.error)
+ return TRUE;
+ if (n_points == 0)
+ {
+ je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
+ return TRUE;
+ }
+
wkb->write_at_position(np_pos, n_points);
return FALSE;
}
@@ -2214,6 +2231,15 @@ bool Gis_multi_line_string::init_from_json(json_engine_t *je, bool er_on_3D,
n_line_strings++;
}
+ if (je->s.error)
+ return TRUE;
+
+ if (n_line_strings == 0)
+ {
+ je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
+ return TRUE;
+ }
+
wkb->write_at_position(ls_pos, n_line_strings);
return FALSE;
}
@@ -2603,6 +2629,13 @@ bool Gis_multi_polygon::init_from_json(json_engine_t *je, bool er_on_3D,
n_polygons++;
}
+ if (je->s.error)
+ return TRUE;
+ if (n_polygons == 0)
+ {
+ je->s.error= Geometry::GEOJ_EMPTY_COORDINATES;
+ return TRUE;
+ }
wkb->write_at_position(np_pos, n_polygons);
return FALSE;
}
diff --git a/sql/spatial.h b/sql/spatial.h
index 78e850dc2d7..901544b6916 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -256,6 +256,7 @@ public:
GEOJ_TOO_FEW_POINTS= 2,
GEOJ_POLYGON_NOT_CLOSED= 3,
GEOJ_DIMENSION_NOT_SUPPORTED= 4,
+ GEOJ_EMPTY_COORDINATES= 5,
};
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index a5265b5a742..9d3299a63d4 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -7596,6 +7596,11 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
INSERT_ACL : SELECT_ACL);
}
+ if (tl->with ||
+ (tl->select_lex &&
+ (tl->with= tl->select_lex->find_table_def_in_with_clauses(tl))))
+ continue;
+
const ACL_internal_table_access *access=
get_cached_table_access(&t_ref->grant.m_internal,
t_ref->get_db_name(),
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index a37d96934ea..25e377be8de 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -387,13 +387,15 @@ public:
/**
Sql_cmd_alter_sequence represents the ALTER SEQUENCE statement.
*/
-class Sql_cmd_alter_sequence : public Sql_cmd
+class Sql_cmd_alter_sequence : public Sql_cmd,
+ public DDL_options
{
public:
/**
Constructor, used to represent a ALTER TABLE statement.
*/
- Sql_cmd_alter_sequence()
+ Sql_cmd_alter_sequence(const DDL_options &options)
+ :DDL_options(options)
{}
~Sql_cmd_alter_sequence()
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 02f49b6d645..9181e3c96d6 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -5029,17 +5029,14 @@ extern "C" int thd_non_transactional_update(const MYSQL_THD thd)
extern "C" int thd_binlog_format(const MYSQL_THD thd)
{
-#ifdef WITH_WSREP
if (WSREP(thd))
{
/* for wsrep binlog format is meaningful also when binlogging is off */
- return (int) WSREP_BINLOG_FORMAT(thd->variables.binlog_format);
+ return (int) thd->wsrep_binlog_format();
}
-#endif /* WITH_WSREP */
if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG))
return (int) thd->variables.binlog_format;
- else
- return BINLOG_FORMAT_UNSPEC;
+ return BINLOG_FORMAT_UNSPEC;
}
extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 306c13e9b5b..038e1648596 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5198,10 +5198,11 @@ public:
select_unit(THD *thd_arg):
select_result_interceptor(thd_arg),
- curr_step(0), prev_step(0), curr_sel(UINT_MAX),
- step(UNION_TYPE), intersect_mark(0), write_err(0), table(0),
- records(0)
- { tmp_table_param.init(); }
+ intersect_mark(0), table(0)
+ {
+ init();
+ tmp_table_param.init();
+ }
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
/**
Do prepare() and prepare2() if they have been postponed until
@@ -5225,6 +5226,14 @@ public:
bool keep_row_order,
uint hidden);
TMP_TABLE_PARAM *get_tmp_table_param() { return &tmp_table_param; }
+ void init()
+ {
+ curr_step= prev_step= 0;
+ curr_sel= UINT_MAX;
+ step= UNION_TYPE;
+ write_err= 0;
+ records= 0;
+ }
void change_select();
};
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index 487c2b3a0bb..ff80e198023 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -839,9 +839,10 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
tbl;
tbl= tbl->next_global)
{
- tbl->grant.privilege= with_table->grant.privilege;
spec_tables_tail= tbl;
}
+ if (check_table_access(thd, SELECT_ACL, spec_tables, FALSE, UINT_MAX, FALSE))
+ goto err;
if (spec_tables)
{
if (with_table->next_global)
diff --git a/sql/sql_get_diagnostics.cc b/sql/sql_get_diagnostics.cc
index 76973b4daa2..e7ab6cc3c75 100644
--- a/sql/sql_get_diagnostics.cc
+++ b/sql/sql_get_diagnostics.cc
@@ -110,6 +110,9 @@ Diagnostics_information_item::set_value(THD *thd, Item **value)
DBUG_ASSERT(srp);
+ /* GET DIAGNOSTICS is not allowed in prepared statements */
+ DBUG_ASSERT(srp->get_item_param() == NULL);
+
/* Set variable/parameter value. */
rv= srp->set_value(thd, thd->spcont, value);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 26ca5a3ad17..6cb065c3985 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -827,6 +827,7 @@ void lex_end_stage2(LEX *lex)
/* Reset LEX_MASTER_INFO */
lex->mi.reset(lex->sql_command == SQLCOM_CHANGE_MASTER);
+ delete_dynamic(&lex->delete_gtid_domain);
DBUG_VOID_RETURN;
}
@@ -3032,6 +3033,10 @@ LEX::LEX()
INITIAL_LEX_PLUGIN_LIST_SIZE, 0);
reset_query_tables_list(TRUE);
mi.init();
+ init_dynamic_array2(&delete_gtid_domain, sizeof(ulong*),
+ gtid_domain_static_buffer,
+ initial_gtid_domain_buffer_size,
+ initial_gtid_domain_buffer_size, 0);
}
@@ -5594,6 +5599,35 @@ sp_variable *LEX::sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name,
}
+bool LEX::sp_for_loop_implicit_cursor_statement(THD *thd,
+ Lex_for_loop_bounds_st *bounds,
+ sp_lex_cursor *cur)
+{
+ Item *item;
+ DBUG_ASSERT(sphead);
+ LEX_CSTRING name= {STRING_WITH_LEN("[implicit_cursor]") };
+ if (sp_declare_cursor(thd, &name, cur, NULL, true))
+ return true;
+ DBUG_ASSERT(thd->lex == this);
+ if (!(bounds->m_index= new (thd->mem_root) sp_assignment_lex(thd, this)))
+ return true;
+ bounds->m_index->sp_lex_in_use= true;
+ sphead->reset_lex(thd, bounds->m_index);
+ DBUG_ASSERT(thd->lex != this);
+ if (!(item= new (thd->mem_root) Item_field(thd,
+ thd->lex->current_context(),
+ NullS, NullS, &name)))
+ return true;
+ bounds->m_index->set_item_and_free_list(item, NULL);
+ if (thd->lex->sphead->restore_lex(thd))
+ return true;
+ DBUG_ASSERT(thd->lex == this);
+ bounds->m_direction= 1;
+ bounds->m_upper_bound= NULL;
+ bounds->m_implicit_cursor= true;
+ return false;
+}
+
sp_variable *
LEX::sp_add_for_loop_cursor_variable(THD *thd,
const LEX_CSTRING *name,
@@ -5805,7 +5839,7 @@ bool LEX::sp_for_loop_cursor_finalize(THD *thd, const Lex_for_loop_st &loop)
{
sp_instr_cfetch *instr=
new (thd->mem_root) sp_instr_cfetch(sphead->instructions(),
- spcont, loop.m_cursor_offset);
+ spcont, loop.m_cursor_offset, false);
if (instr == NULL || sphead->add_instr(instr))
return true;
instr->add_to_varlist(loop.m_index);
@@ -6452,6 +6486,11 @@ Item *LEX::create_and_link_Item_trigger_field(THD *thd,
Item_param *LEX::add_placeholder(THD *thd, const LEX_CSTRING *name,
const char *start, const char *end)
{
+ if (!thd->m_parser_state->m_lip.stmt_prepare_mode)
+ {
+ thd->parse_error(ER_SYNTAX_ERROR, start);
+ return NULL;
+ }
if (!parsing_options.allows_variable)
{
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
@@ -7278,7 +7317,8 @@ bool LEX::sp_add_cfetch(THD *thd, const LEX_CSTRING *name)
return true;
}
i= new (thd->mem_root)
- sp_instr_cfetch(sphead->instructions(), spcont, offset);
+ sp_instr_cfetch(sphead->instructions(), spcont, offset,
+ !(thd->variables.sql_mode & MODE_ORACLE));
if (i == NULL || sphead->add_instr(i))
return true;
return false;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 6233417bb80..2ec287e786b 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -2949,6 +2949,13 @@ public:
*/
Item *limit_rows_examined;
ulonglong limit_rows_examined_cnt;
+ /**
+ Holds a set of domain_ids for deletion at FLUSH..DELETE_DOMAIN_ID
+ */
+ DYNAMIC_ARRAY delete_gtid_domain;
+ static const ulong initial_gtid_domain_buffer_size= 16;
+ ulong gtid_domain_static_buffer[initial_gtid_domain_buffer_size];
+
inline void set_limit_rows_examined()
{
if (limit_rows_examined)
@@ -3473,6 +3480,9 @@ public:
uint coffset,
sp_assignment_lex *param_lex,
Item_args *parameters);
+ bool sp_for_loop_implicit_cursor_statement(THD *thd,
+ Lex_for_loop_bounds_st *bounds,
+ sp_lex_cursor *cur);
bool sp_for_loop_cursor_condition_test(THD *thd, const Lex_for_loop_st &loop);
bool sp_for_loop_cursor_finalize(THD *thd, const Lex_for_loop_st &);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b3a9ad144d5..346d1c0f18f 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3729,6 +3729,14 @@ mysql_execute_command(THD *thd)
ulong privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL :
SELECT_ACL;
+ /*
+ The same function must be called for DML commands
+ when CTEs are supported in DML statements
+ */
+ res= check_dependencies_in_with_clauses(thd->lex->with_clauses_list);
+ if (res)
+ break;
+
if (all_tables)
res= check_table_access(thd,
privileges_requested,
@@ -6279,6 +6287,24 @@ finish:
THD_STAGE_INFO(thd, stage_rollback);
trans_rollback_stmt(thd);
}
+#ifdef WITH_WSREP
+ else if (thd->spcont &&
+ (thd->wsrep_conflict_state == MUST_ABORT ||
+ thd->wsrep_conflict_state == CERT_FAILURE))
+ {
+ /*
+ The error was cleared, but THD was aborted by wsrep and
+ wsrep_conflict_state is still set accordingly. This
+ situation is expected if we are running a stored procedure
+ that declares a handler that catches ER_LOCK_DEADLOCK error.
+ In which case the error may have been cleared in method
+ sp_rcontext::handle_sql_condition().
+ */
+ trans_rollback_stmt(thd);
+ thd->wsrep_conflict_state= NO_CONFLICT;
+ thd->killed= NOT_KILLED;
+ }
+#endif /* WITH_WSREP */
else
{
/* If commit fails, we should be able to reset the OK status. */
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 775717fe62b..243d9d524c2 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -489,24 +489,23 @@ static ulong get_param_length(uchar **packet, ulong len)
(i.e. when input types altered) and for all subsequent executions
we don't read any values for this.
- @param param parameter item
@param pos input data buffer
@param len length of data in the buffer
*/
-static void set_param_tiny(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_tiny(uchar **pos, ulong len)
{
#ifndef EMBEDDED_LIBRARY
if (len < 1)
return;
#endif
int8 value= (int8) **pos;
- param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) :
- (longlong) value, 4);
+ set_int(unsigned_flag ? (longlong) ((uint8) value) :
+ (longlong) value, 4);
*pos+= 1;
}
-static void set_param_short(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_short(uchar **pos, ulong len)
{
int16 value;
#ifndef EMBEDDED_LIBRARY
@@ -516,12 +515,12 @@ static void set_param_short(Item_param *param, uchar **pos, ulong len)
#else
shortget(value, *pos);
#endif
- param->set_int(param->unsigned_flag ? (longlong) ((uint16) value) :
- (longlong) value, 6);
+ set_int(unsigned_flag ? (longlong) ((uint16) value) :
+ (longlong) value, 6);
*pos+= 2;
}
-static void set_param_int32(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_int32(uchar **pos, ulong len)
{
int32 value;
#ifndef EMBEDDED_LIBRARY
@@ -531,12 +530,12 @@ static void set_param_int32(Item_param *param, uchar **pos, ulong len)
#else
longget(value, *pos);
#endif
- param->set_int(param->unsigned_flag ? (longlong) ((uint32) value) :
- (longlong) value, 11);
+ set_int(unsigned_flag ? (longlong) ((uint32) value) :
+ (longlong) value, 11);
*pos+= 4;
}
-static void set_param_int64(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_int64(uchar **pos, ulong len)
{
longlong value;
#ifndef EMBEDDED_LIBRARY
@@ -546,11 +545,11 @@ static void set_param_int64(Item_param *param, uchar **pos, ulong len)
#else
longlongget(value, *pos);
#endif
- param->set_int(value, 21);
+ set_int(value, 21);
*pos+= 8;
}
-static void set_param_float(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_float(uchar **pos, ulong len)
{
float data;
#ifndef EMBEDDED_LIBRARY
@@ -560,11 +559,11 @@ static void set_param_float(Item_param *param, uchar **pos, ulong len)
#else
floatget(data, *pos);
#endif
- param->set_double((double) data);
+ set_double((double) data);
*pos+= 4;
}
-static void set_param_double(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_double(uchar **pos, ulong len)
{
double data;
#ifndef EMBEDDED_LIBRARY
@@ -574,14 +573,14 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len)
#else
doubleget(data, *pos);
#endif
- param->set_double((double) data);
+ set_double((double) data);
*pos+= 8;
}
-static void set_param_decimal(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_decimal(uchar **pos, ulong len)
{
ulong length= get_param_length(pos, len);
- param->set_decimal((char*)*pos, length);
+ set_decimal((char*)*pos, length);
*pos+= length;
}
@@ -597,7 +596,7 @@ static void set_param_decimal(Item_param *param, uchar **pos, ulong len)
@todo
Add warning 'Data truncated' here
*/
-static void set_param_time(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_time(uchar **pos, ulong len)
{
MYSQL_TIME tm;
ulong length= get_param_length(pos, len);
@@ -624,11 +623,11 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
}
else
set_zero_time(&tm, MYSQL_TIMESTAMP_TIME);
- param->set_time(&tm, MYSQL_TIMESTAMP_TIME, MAX_TIME_FULL_WIDTH);
+ set_time(&tm, MYSQL_TIMESTAMP_TIME, MAX_TIME_FULL_WIDTH);
*pos+= length;
}
-static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_datetime(uchar **pos, ulong len)
{
MYSQL_TIME tm;
ulong length= get_param_length(pos, len);
@@ -654,13 +653,12 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
}
else
set_zero_time(&tm, MYSQL_TIMESTAMP_DATETIME);
- param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
- MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
+ set_time(&tm, MYSQL_TIMESTAMP_DATETIME, MAX_DATETIME_WIDTH);
*pos+= length;
}
-static void set_param_date(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_date(uchar **pos, ulong len)
{
MYSQL_TIME tm;
ulong length= get_param_length(pos, len);
@@ -679,8 +677,7 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
}
else
set_zero_time(&tm, MYSQL_TIMESTAMP_DATE);
- param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
- MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
+ set_time(&tm, MYSQL_TIMESTAMP_DATE, MAX_DATE_WIDTH);
*pos+= length;
}
@@ -689,7 +686,7 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
@todo
Add warning 'Data truncated' here
*/
-void set_param_time(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_time(uchar **pos, ulong len)
{
MYSQL_TIME tm= *((MYSQL_TIME*)*pos);
tm.hour+= tm.day * 24;
@@ -701,145 +698,81 @@ void set_param_time(Item_param *param, uchar **pos, ulong len)
tm.minute= 59;
tm.second= 59;
}
- param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
- MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
-
+ set_time(&tm, MYSQL_TIMESTAMP_TIME, MAX_TIME_WIDTH);
}
-void set_param_datetime(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_datetime(uchar **pos, ulong len)
{
MYSQL_TIME tm= *((MYSQL_TIME*)*pos);
tm.neg= 0;
-
- param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
- MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
+ set_time(&tm, MYSQL_TIMESTAMP_DATETIME, MAX_DATETIME_WIDTH);
}
-void set_param_date(Item_param *param, uchar **pos, ulong len)
+void Item_param::set_param_date(uchar **pos, ulong len)
{
MYSQL_TIME *to= (MYSQL_TIME*)*pos;
-
- param->set_time(to, MYSQL_TIMESTAMP_DATE,
- MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
+ set_time(to, MYSQL_TIMESTAMP_DATE, MAX_DATE_WIDTH);
}
#endif /*!EMBEDDED_LIBRARY*/
-static void set_param_str_or_null(Item_param *param, uchar **pos, ulong len,
- bool empty_string_is_null)
+void Item_param::set_param_str(uchar **pos, ulong len)
{
ulong length= get_param_length(pos, len);
- if (length == 0 && empty_string_is_null)
- param->set_null();
+ if (length == 0 && m_empty_string_is_null)
+ set_null();
else
{
if (length > len)
length= len;
- param->set_str((const char *) *pos, length);
+ /*
+ We use &my_charset_bin here. Conversion and setting real character
+ sets will be done in Item_param::convert_str_value(), after the
+ original value is appended to the query used for logging.
+ */
+ set_str((const char *) *pos, length, &my_charset_bin, &my_charset_bin);
*pos+= length;
}
}
-static void set_param_str(Item_param *param, uchar **pos, ulong len)
-{
- set_param_str_or_null(param, pos, len, false);
-}
+#undef get_param_length
-/*
- set_param_str_empty_is_null : bind empty string as null value
- when sql_mode=MODE_EMPTY_STRING_IS_NULL
-*/
-static void set_param_str_empty_is_null(Item_param *param, uchar **pos,
- ulong len)
+void Item_param::setup_conversion(THD *thd, uchar param_type)
{
- set_param_str_or_null(param, pos, len, true);
+ const Type_handler *h=
+ Type_handler::get_handler_by_field_type((enum_field_types) param_type);
+ /*
+ The client library ensures that we won't get any unexpected typecodes
+ in the bound parameter. Translating unknown typecodes to
+ &type_handler_string lets us to handle malformed packets as well.
+ */
+ if (!h)
+ h= &type_handler_string;
+ set_handler(h);
+ h->Item_param_setup_conversion(thd, this);
}
-#undef get_param_length
-
-static void setup_one_conversion_function(THD *thd, Item_param *param,
- uchar param_type)
+void Item_param::setup_conversion_blob(THD *thd)
{
- switch (param_type) {
- case MYSQL_TYPE_TINY:
- param->set_param_func= set_param_tiny;
- break;
- case MYSQL_TYPE_SHORT:
- param->set_param_func= set_param_short;
- break;
- case MYSQL_TYPE_LONG:
- param->set_param_func= set_param_int32;
- break;
- case MYSQL_TYPE_LONGLONG:
- param->set_param_func= set_param_int64;
- break;
- case MYSQL_TYPE_FLOAT:
- param->set_param_func= set_param_float;
- break;
- case MYSQL_TYPE_DOUBLE:
- param->set_param_func= set_param_double;
- break;
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- param->set_param_func= set_param_decimal;
- break;
- case MYSQL_TYPE_TIME:
- param->set_param_func= set_param_time;
- break;
- case MYSQL_TYPE_DATE:
- param->set_param_func= set_param_date;
- break;
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- param->set_param_func= set_param_datetime;
- break;
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- param->set_param_func= set_param_str;
- param->value.cs_info.character_set_of_placeholder= &my_charset_bin;
- param->value.cs_info.character_set_client=
- thd->variables.character_set_client;
- DBUG_ASSERT(thd->variables.character_set_client);
- param->value.cs_info.final_character_set_of_str_value= &my_charset_bin;
- break;
- default:
- /*
- The client library ensures that we won't get any other typecodes
- except typecodes above and typecodes for string types. Marking
- label as 'default' lets us to handle malformed packets as well.
- */
- {
- CHARSET_INFO *fromcs= thd->variables.character_set_client;
- CHARSET_INFO *tocs= thd->variables.collation_connection;
- uint32 dummy_offset;
+ value.cs_info.character_set_of_placeholder= &my_charset_bin;
+ value.cs_info.character_set_client= thd->variables.character_set_client;
+ DBUG_ASSERT(thd->variables.character_set_client);
+ value.cs_info.final_character_set_of_str_value= &my_charset_bin;
+ m_empty_string_is_null= thd->variables.sql_mode & MODE_EMPTY_STRING_IS_NULL;
+}
- param->value.cs_info.character_set_of_placeholder= fromcs;
- param->value.cs_info.character_set_client= fromcs;
- /*
- Setup source and destination character sets so that they
- are different only if conversion is necessary: this will
- make later checks easier.
- */
- param->value.cs_info.final_character_set_of_str_value=
- String::needs_conversion(0, fromcs, tocs, &dummy_offset) ?
- tocs : fromcs;
-
- param->set_param_func=
- (thd->variables.sql_mode & MODE_EMPTY_STRING_IS_NULL) ?
- set_param_str_empty_is_null : set_param_str;
- /*
- Exact value of max_length is not known unless data is converted to
- charset of connection, so we have to set it later.
- */
- }
- }
- param->set_handler_by_field_type((enum enum_field_types) param_type);
+void Item_param::setup_conversion_string(THD *thd, CHARSET_INFO *fromcs)
+{
+ value.cs_info.set(thd, fromcs);
+ m_empty_string_is_null= thd->variables.sql_mode & MODE_EMPTY_STRING_IS_NULL;
+ /*
+ Exact value of max_length is not known unless data is converted to
+ charset of connection, so we have to set it later.
+ */
}
#ifndef EMBEDDED_LIBRARY
@@ -903,14 +836,13 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
{
if (read_pos >= data_end)
DBUG_RETURN(1);
- param->set_param_func(param, &read_pos, (uint) (data_end - read_pos));
+ param->set_param_func(&read_pos, (uint) (data_end - read_pos));
if (param->has_no_value())
DBUG_RETURN(1);
if (param->limit_clause_param && !param->has_int_value())
{
- param->set_int(param->val_int(), MY_INT64_NUM_DECIMAL_DIGITS);
- if (!param->unsigned_flag && param->value.integer < 0)
+ if (param->set_limit_clause_param(param->val_int()))
DBUG_RETURN(1);
}
}
@@ -958,7 +890,7 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array,
{
if (read_pos >= data_end)
DBUG_RETURN(1);
- param->set_param_func(param, &read_pos, (uint) (data_end - read_pos));
+ param->set_param_func(&read_pos, (uint) (data_end - read_pos));
if (param->has_no_value())
DBUG_RETURN(1);
}
@@ -1002,7 +934,7 @@ static bool insert_bulk_params(Prepared_statement *stmt,
case STMT_INDICATOR_NONE:
if ((*read_pos) >= data_end)
DBUG_RETURN(1);
- param->set_param_func(param, read_pos, (uint) (data_end - (*read_pos)));
+ param->set_param_func(read_pos, (uint) (data_end - (*read_pos)));
if (param->has_no_value())
DBUG_RETURN(1);
if (param->convert_str_value(stmt->thd))
@@ -1048,7 +980,7 @@ static bool set_conversion_functions(Prepared_statement *stmt,
typecode= sint2korr(read_pos);
read_pos+= 2;
(**it).unsigned_flag= MY_TEST(typecode & signed_bit);
- setup_one_conversion_function(thd, *it, (uchar) (typecode & 0xff));
+ (*it)->setup_conversion(thd, (uchar) (typecode & 0xff));
}
*data= read_pos;
DBUG_RETURN(0);
@@ -1103,7 +1035,7 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
for (; it < end; ++it, ++client_param)
{
Item_param *param= *it;
- setup_one_conversion_function(thd, param, client_param->buffer_type);
+ param->setup_conversion(thd, client_param->buffer_type);
if (!param->has_long_data_value())
{
if (*client_param->is_null)
@@ -1112,7 +1044,7 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
{
uchar *buff= (uchar*) client_param->buffer;
param->unsigned_flag= client_param->is_unsigned;
- param->set_param_func(param, &buff,
+ param->set_param_func(&buff,
client_param->length ?
*client_param->length :
client_param->buffer_length);
@@ -1139,7 +1071,7 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt, String *query)
for (; it < end; ++it, ++client_param)
{
Item_param *param= *it;
- setup_one_conversion_function(thd, param, client_param->buffer_type);
+ param->setup_conversion(thd, client_param->buffer_type);
if (!param->has_long_data_value())
{
if (*client_param->is_null)
@@ -1148,7 +1080,7 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt, String *query)
{
uchar *buff= (uchar*)client_param->buffer;
param->unsigned_flag= client_param->is_unsigned;
- param->set_param_func(param, &buff,
+ param->set_param_func(&buff,
client_param->length ?
*client_param->length :
client_param->buffer_length);
@@ -1281,12 +1213,6 @@ insert_params_from_actual_params_with_log(Prepared_statement *stmt,
{
Item_param *param= *it;
Item *ps_param= param_it++;
- /*
- We have to call the setup_one_conversion_function() here to set
- the parameter's members that might be needed further
- (e.g. value.cs_info.character_set_client is used in the query_val_str()).
- */
- setup_one_conversion_function(thd, param, param->field_type());
if (ps_param->save_in_param(thd, param))
DBUG_RETURN(1);
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index 057d1a9f46c..93db089b24a 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -153,7 +153,10 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
tmp_write_to_binlog= 0;
if (mysql_bin_log.is_open())
{
- if (mysql_bin_log.rotate_and_purge(true))
+ DYNAMIC_ARRAY *drop_gtid_domain=
+ (thd && (thd->lex->delete_gtid_domain.elements > 0)) ?
+ &thd->lex->delete_gtid_domain : NULL;
+ if (mysql_bin_log.rotate_and_purge(true, drop_gtid_domain))
*write_to_binlog= -1;
if (WSREP_ON)
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 839b98dc785..d978a2d58ee 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -30,7 +30,7 @@
#include <my_dir.h>
#include "rpl_handler.h"
#include "debug_sync.h"
-
+#include "log.h" // get_gtid_list_event
enum enum_gtid_until_state {
GTID_UNTIL_NOT_DONE,
@@ -875,72 +875,6 @@ get_binlog_list(MEM_ROOT *memroot)
DBUG_RETURN(current_list);
}
-/*
- Find the Gtid_list_log_event at the start of a binlog.
-
- NULL for ok, non-NULL error message for error.
-
- If ok, then the event is returned in *out_gtid_list. This can be NULL if we
- get back to binlogs written by old server version without GTID support. If
- so, it means we have reached the point to start from, as no GTID events can
- exist in earlier binlogs.
-*/
-static const char *
-get_gtid_list_event(IO_CACHE *cache, Gtid_list_log_event **out_gtid_list)
-{
- Format_description_log_event init_fdle(BINLOG_VERSION);
- Format_description_log_event *fdle;
- Log_event *ev;
- const char *errormsg = NULL;
-
- *out_gtid_list= NULL;
-
- if (!(ev= Log_event::read_log_event(cache, 0, &init_fdle,
- opt_master_verify_checksum)) ||
- ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
- {
- if (ev)
- delete ev;
- return "Could not read format description log event while looking for "
- "GTID position in binlog";
- }
-
- fdle= static_cast<Format_description_log_event *>(ev);
-
- for (;;)
- {
- Log_event_type typ;
-
- ev= Log_event::read_log_event(cache, 0, fdle, opt_master_verify_checksum);
- if (!ev)
- {
- errormsg= "Could not read GTID list event while looking for GTID "
- "position in binlog";
- break;
- }
- typ= ev->get_type_code();
- if (typ == GTID_LIST_EVENT)
- break; /* Done, found it */
- if (typ == START_ENCRYPTION_EVENT)
- {
- if (fdle->start_decryption((Start_encryption_log_event*) ev))
- errormsg= "Could not set up decryption for binlog.";
- }
- delete ev;
- if (typ == ROTATE_EVENT || typ == STOP_EVENT ||
- typ == FORMAT_DESCRIPTION_EVENT || typ == START_ENCRYPTION_EVENT)
- continue; /* Continue looking */
-
- /* We did not find any Gtid_list_log_event, must be old binlog. */
- ev= NULL;
- break;
- }
-
- delete fdle;
- *out_gtid_list= static_cast<Gtid_list_log_event *>(ev);
- return errormsg;
-}
-
/*
Check if every GTID requested by the slave is contained in this (or a later)
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index 4105bdddf4e..8d9a127bca7 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -81,7 +81,6 @@ int rpl_append_gtid_state(String *dest, bool use_binlog);
int rpl_load_gtid_state(slave_connection_state *state, bool use_binlog);
bool rpl_gtid_pos_check(THD *thd, char *str, size_t len);
bool rpl_gtid_pos_update(THD *thd, char *str, size_t len);
-
#else
struct LOAD_FILE_IO_CACHE : public IO_CACHE { };
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index ff9af8a33b9..1a29dcb62ab 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -12857,7 +12857,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
*simple_order=0; // Must do a temp table to sort
else if (!(order_tables & not_const_tables))
{
- if (order->item[0]->has_subquery())
+ if (order->item[0]->with_subquery())
{
/*
Delay the evaluation of constant ORDER and/or GROUP expressions that
@@ -12895,8 +12895,37 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
can be used without tmp. table.
*/
bool can_subst_to_first_table= false;
+ bool first_is_in_sjm_nest= false;
+ if (first_is_base_table)
+ {
+ TABLE_LIST *tbl_for_first=
+ join->join_tab[join->const_tables].table->pos_in_table_list;
+ first_is_in_sjm_nest= tbl_for_first->sj_mat_info &&
+ tbl_for_first->sj_mat_info->is_used;
+ }
+ /*
+ Currently we do not employ the optimization that uses multiple
+ equalities for ORDER BY to remove tmp table in the case when
+ the first table happens to be the result of materialization of
+ a semi-join nest ( <=> first_is_in_sjm_nest == true).
+
+ When a semi-join nest is materialized and scanned to look for
+ possible matches in the remaining tables for every its row
+ the fields from the result of materialization are copied
+ into the record buffers of tables from the semi-join nest.
+ So these copies are used to access the remaining tables rather
+ than the fields from the result of materialization.
+
+ Unfortunately now this so-called 'copy back' technique is
+ supported only if the rows are scanned with the rr_sequential
+ function, but not with other rr_* functions that are employed
+ when the result of materialization is required to be sorted.
+
+ TODO: either to support 'copy back' technique for the above case,
+ or to get rid of this technique altogether.
+ */
if (optimizer_flag(join->thd, OPTIMIZER_SWITCH_ORDERBY_EQ_PROP) &&
- first_is_base_table &&
+ first_is_base_table && !first_is_in_sjm_nest &&
order->item[0]->real_item()->type() == Item::FIELD_ITEM &&
join->cond_equal)
{
diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc
index e2d3f225e47..de4cd3522a5 100644
--- a/sql/sql_sequence.cc
+++ b/sql/sql_sequence.cc
@@ -852,10 +852,10 @@ bool Sql_cmd_alter_sequence::execute(THD *thd)
if (check_grant(thd, ALTER_ACL, first_table, FALSE, 1, FALSE))
DBUG_RETURN(TRUE); /* purecov: inspected */
- if (lex->check_exists)
+ if (if_exists())
thd->push_internal_handler(&no_such_table_handler);
error= open_and_lock_tables(thd, first_table, FALSE, 0);
- if (lex->check_exists)
+ if (if_exists())
{
trapped_errors= no_such_table_handler.safely_trapped_errors();
thd->pop_internal_handler();
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 2df84b473b8..c88991f7795 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -5201,12 +5201,13 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
if (share->tmp_table == SYSTEM_TMP_TABLE)
table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs);
- else if (share->tmp_table)
- table->field[3]->store(STRING_WITH_LEN("LOCAL TEMPORARY"), cs);
else if (share->table_type == TABLE_TYPE_SEQUENCE)
table->field[3]->store(STRING_WITH_LEN("SEQUENCE"), cs);
else
+ {
+ DBUG_ASSERT(share->tmp_table == NO_TMP_TABLE);
table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs);
+ }
for (int i= 4; i < 20; i++)
{
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 62dcff33f1d..e84bdb1455d 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -4376,7 +4376,7 @@ bool Type_handler::
bool Type_handler::
Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
{
- item->fix_length_and_dec_str();
+ item->fix_length_and_dec_generic();
return false;
}
@@ -4389,6 +4389,14 @@ bool Type_handler_numeric::
}
+bool Type_handler_string_result::
+ Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
+{
+ item->fix_length_and_dec_str();
+ return false;
+}
+
+
bool Type_handler::
Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const
{
@@ -5044,7 +5052,6 @@ bool Type_handler_real_result::
{
param->unsigned_flag= attr->unsigned_flag;
param->set_double(val->value.m_double);
- param->set_handler(&type_handler_double);
return false;
}
@@ -5056,8 +5063,7 @@ bool Type_handler_int_result::
const st_value *val) const
{
param->unsigned_flag= attr->unsigned_flag;
- param->set_int(val->value.m_longlong, MY_INT64_NUM_DECIMAL_DIGITS);
- param->set_handler(&type_handler_longlong);
+ param->set_int(val->value.m_longlong, attr->max_length);
return false;
}
@@ -5070,7 +5076,6 @@ bool Type_handler_decimal_result::
{
param->unsigned_flag= attr->unsigned_flag;
param->set_decimal(&val->m_decimal, attr->unsigned_flag);
- param->set_handler(&type_handler_newdecimal);
return false;
}
@@ -5082,13 +5087,14 @@ bool Type_handler_string_result::
const st_value *val) const
{
param->unsigned_flag= false;
- param->value.cs_info.set(thd, attr->collation.collation);
+ param->setup_conversion_string(thd, attr->collation.collation);
/*
Exact value of max_length is not known unless data is converted to
charset of connection, so we have to set it later.
*/
- param->set_handler(&type_handler_varchar);
- return param->set_str(val->m_string.ptr(), val->m_string.length());
+ return param->set_str(val->m_string.ptr(), val->m_string.length(),
+ attr->collation.collation,
+ attr->collation.collation);
}
@@ -5100,7 +5106,6 @@ bool Type_handler_temporal_result::
{
param->unsigned_flag= attr->unsigned_flag;
param->set_time(&val->value.m_time, attr->max_length, attr->decimals);
- param->set_handler(this);
return false;
}
@@ -5113,10 +5118,10 @@ bool Type_handler_geometry::
const st_value *val) const
{
param->unsigned_flag= false;
- param->value.cs_info.set(thd, &my_charset_bin);
- param->set_handler(&type_handler_geometry);
+ param->setup_conversion_blob(thd);
param->set_geometry_type(attr->uint_geometry_type());
- return param->set_str(val->m_string.ptr(), val->m_string.length());
+ return param->set_str(val->m_string.ptr(), val->m_string.length(),
+ &my_charset_bin, &my_charset_bin);
}
#endif
@@ -5502,3 +5507,139 @@ Item *Type_handler_long_blob::
}
/***************************************************************************/
+
+void Type_handler_string_result::Item_param_setup_conversion(THD *thd,
+ Item_param *param)
+ const
+{
+ param->setup_conversion_string(thd, thd->variables.character_set_client);
+}
+
+
+void Type_handler_blob_common::Item_param_setup_conversion(THD *thd,
+ Item_param *param)
+ const
+{
+ param->setup_conversion_blob(thd);
+}
+
+
+void Type_handler_tiny::Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const
+{
+ param->set_param_tiny(pos, len);
+}
+
+
+void Type_handler_short::Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const
+{
+ param->set_param_short(pos, len);
+}
+
+
+void Type_handler_long::Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const
+{
+ param->set_param_int32(pos, len);
+}
+
+
+void Type_handler_longlong::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_int64(pos, len);
+}
+
+
+void Type_handler_float::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_float(pos, len);
+}
+
+
+void Type_handler_double::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_double(pos, len);
+}
+
+
+void Type_handler_decimal_result::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_decimal(pos, len);
+}
+
+
+void Type_handler_string_result::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_str(pos, len);
+}
+
+
+void Type_handler_time_common::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_time(pos, len);
+}
+
+
+void Type_handler_date_common::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_date(pos, len);
+}
+
+
+void Type_handler_datetime_common::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_datetime(pos, len);
+}
+
+
+void Type_handler_timestamp_common::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_param_datetime(pos, len);
+}
+
+
+void Type_handler::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_null(); // Not possible type code in the client-server protocol
+}
+
+
+void Type_handler_typelib::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_null(); // Not possible type code in the client-server protocol
+}
+
+
+#ifdef HAVE_SPATIAL
+void Type_handler_geometry::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_null(); // Not possible type code in the client-server protocol
+}
+#endif
+
+/***************************************************************************/
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 7c6d1a69f23..427d59718f6 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -804,6 +804,9 @@ public:
virtual uint32 max_display_length(const Item *item) const= 0;
virtual uint32 calc_pack_length(uint32 length) const= 0;
virtual bool Item_save_in_value(Item *item, st_value *value) const= 0;
+ virtual void Item_param_setup_conversion(THD *thd, Item_param *) const {}
+ virtual void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
virtual bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
@@ -1422,6 +1425,8 @@ public:
const Type_cast_attributes &attr) const;
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
@@ -1658,6 +1663,9 @@ public:
}
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
+ void Item_param_setup_conversion(THD *thd, Item_param *) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
@@ -1716,6 +1724,7 @@ public:
MYSQL_TIME *, ulonglong fuzzydate) const;
bool Item_func_between_fix_length_and_dec(Item_func_between *func) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
+ bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
@@ -1783,6 +1792,8 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
};
@@ -1810,6 +1821,8 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
};
@@ -1840,6 +1853,8 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
};
@@ -1871,6 +1886,8 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
};
@@ -1994,6 +2011,8 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
};
@@ -2024,6 +2043,8 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
};
@@ -2068,6 +2089,8 @@ public:
bool set_comparator_func(Arg_comparator *cmp) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
};
@@ -2151,6 +2174,8 @@ public:
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
};
class Type_handler_date: public Type_handler_date_common
@@ -2225,6 +2250,8 @@ public:
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
};
@@ -2305,6 +2332,8 @@ public:
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
};
@@ -2573,6 +2602,7 @@ public:
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
+ void Item_param_setup_conversion(THD *thd, Item_param *) const;
};
@@ -2674,6 +2704,8 @@ public:
{
return false; // Materialization does not work with GEOMETRY columns
}
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
@@ -2753,6 +2785,8 @@ public:
const handler *file,
const Schema_specification_st *schema)
const;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const;
};
@@ -2819,6 +2853,10 @@ public:
Type_handler_hybrid_field_type(const Type_handler_hybrid_field_type *other)
:m_type_handler(other->m_type_handler)
{ }
+ void swap(Type_handler_hybrid_field_type &other)
+ {
+ swap_variables(const Type_handler *, m_type_handler, other.m_type_handler);
+ }
const Type_handler *type_handler() const { return m_type_handler; }
enum_field_types real_field_type() const
{
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 40f4f984e0a..d987636a2ac 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -303,7 +303,8 @@ int select_union_recursive::send_data(List<Item> &values)
{
int rc= select_unit::send_data(values);
- if (write_err != HA_ERR_FOUND_DUPP_KEY &&
+ if (rc == 0 &&
+ write_err != HA_ERR_FOUND_DUPP_KEY &&
write_err != HA_ERR_FOUND_DUPP_UNIQUE)
{
int err;
@@ -1360,6 +1361,9 @@ bool st_select_lex_unit::exec()
if (saved_error)
DBUG_RETURN(saved_error);
+ if (union_result)
+ union_result->init();
+
if (uncacheable || !item || !item->assigned() || describe)
{
if (!fake_select_lex && !(with_element && with_element->is_recursive))
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 6ee99a9b29a..a6f34e12f72 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -867,10 +867,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
- Currently there are 102 shift/reduce conflicts.
+ Currently there are 104 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 102
+%expect 104
/*
Comments for TOKENS.
@@ -1028,6 +1028,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token DEFINER_SYM
%token DELAYED_SYM
%token DELAY_KEY_WRITE_SYM
+%token DELETE_DOMAIN_ID_SYM
%token DELETE_SYM /* SQL-2003-R */
%token DENSE_RANK_SYM
%token DESC /* SQL-2003-N */
@@ -1622,11 +1623,15 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident_or_text
IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
opt_component key_cache_name
- sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
+ sp_opt_label BIN_NUM TEXT_STRING_filesystem ident_or_empty
opt_constraint constraint opt_ident
sp_decl_ident
sp_block_label opt_place opt_db
+%type <lex_str>
+ label_ident
+ sp_label
+
%type <lex_string_with_metadata>
TEXT_STRING
NCHAR_STRING
@@ -1767,6 +1772,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <assignment_lex>
assignment_source_lex
assignment_source_expr
+ for_loop_bound_expr
%type <sp_assignment_lex_list>
cursor_actual_parameters
@@ -1918,7 +1924,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
parse_vcol_expr vcol_opt_specifier vcol_opt_attribute
vcol_opt_attribute_list vcol_attribute
opt_serial_attribute opt_serial_attribute_list serial_attribute
- explainable_command opt_lock_wait_timeout
+ explainable_command
+ opt_lock_wait_timeout
+ opt_delete_gtid_domain
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
@@ -1943,6 +1951,9 @@ END_OF_INPUT
%type <spblock> sp_decls sp_decl sp_decl_body sp_decl_variable_list
%type <spname> sp_name
%type <spvar> sp_param_name sp_param_name_and_type
+%type <for_loop> sp_for_loop_index_and_bounds
+%type <for_loop_bounds> sp_for_loop_bounds
+%type <num> opt_sp_for_loop_direction
%type <spvar_mode> sp_opt_inout
%type <index_hint> index_hint_type
%type <num> index_hint_clause normal_join inner_join
@@ -3938,6 +3949,22 @@ assignment_source_expr:
}
;
+for_loop_bound_expr:
+ assignment_source_lex
+ {
+ Lex->sphead->reset_lex(thd, $1);
+ }
+ expr
+ {
+ DBUG_ASSERT($1 == thd->lex);
+ $$= $1;
+ $$->sp_lex_in_use= true;
+ $$->set_item_and_free_list($3, NULL);
+ if ($$->sphead->restore_lex(thd))
+ MYSQL_YYABORT;
+ }
+ ;
+
cursor_actual_parameters:
assignment_source_expr
{
@@ -4237,13 +4264,17 @@ else_clause_opt:
| ELSE sp_proc_stmts1
;
+sp_label:
+ label_ident ':' { $$= $1; }
+ ;
+
sp_opt_label:
/* Empty */ { $$= null_clex_str; }
| label_ident { $$= $1; }
;
sp_block_label:
- label_ident ':'
+ sp_label
{
if (Lex->spcont->block_label_declare(&$1))
MYSQL_YYABORT;
@@ -4297,6 +4328,43 @@ sp_unlabeled_block_not_atomic:
}
;
+/* This adds one shift/reduce conflict */
+opt_sp_for_loop_direction:
+ /* Empty */ { $$= 1; }
+ | REVERSE_SYM { $$= -1; }
+ ;
+
+sp_for_loop_index_and_bounds:
+ ident sp_for_loop_bounds
+ {
+ if (Lex->sp_for_loop_declarations(thd, &$$, &$1, $2))
+ MYSQL_YYABORT;
+ }
+ ;
+
+sp_for_loop_bounds:
+ IN_SYM opt_sp_for_loop_direction for_loop_bound_expr
+ DOT_DOT_SYM for_loop_bound_expr
+ {
+ $$.m_direction= $2;
+ $$.m_index= $3;
+ $$.m_upper_bound= $5;
+ $$.m_implicit_cursor= false;
+ }
+ | IN_SYM opt_sp_for_loop_direction for_loop_bound_expr
+ {
+ $$.m_direction= $2;
+ $$.m_index= $3;
+ $$.m_upper_bound= NULL;
+ $$.m_implicit_cursor= false;
+ }
+ | IN_SYM opt_sp_for_loop_direction '(' sp_cursor_stmt ')'
+ {
+ if (Lex->sp_for_loop_implicit_cursor_statement(thd, &$$, $4))
+ MYSQL_YYABORT;
+ }
+ ;
+
loop_body:
sp_proc_stmts1 END LOOP_SYM
{
@@ -4356,14 +4424,14 @@ pop_sp_loop_label:
;
sp_labeled_control:
- label_ident ':' LOOP_SYM
+ sp_label LOOP_SYM
{
if (Lex->sp_push_loop_label(thd, &$1))
MYSQL_YYABORT;
}
loop_body pop_sp_loop_label
{ }
- | label_ident ':' WHILE_SYM
+ | sp_label WHILE_SYM
{
if (Lex->sp_push_loop_label(thd, &$1))
MYSQL_YYABORT;
@@ -4371,7 +4439,33 @@ sp_labeled_control:
}
while_body pop_sp_loop_label
{ }
- | label_ident ':' REPEAT_SYM
+ | sp_label FOR_SYM
+ {
+ // See "The FOR LOOP statement" comments in sql_lex.cc
+ Lex->sp_block_init(thd); // The outer DECLARE..BEGIN..END block
+ }
+ sp_for_loop_index_and_bounds
+ {
+ if (Lex->sp_push_loop_label(thd, &$1)) // The inner WHILE block
+ MYSQL_YYABORT;
+ if (Lex->sp_for_loop_condition_test(thd, $4))
+ MYSQL_YYABORT;
+ }
+ DO_SYM
+ sp_proc_stmts1
+ END FOR_SYM
+ {
+ if (Lex->sp_for_loop_finalize(thd, $4))
+ MYSQL_YYABORT;
+ }
+ pop_sp_loop_label // The inner WHILE block
+ {
+ Lex_spblock tmp;
+ tmp.curs= MY_TEST($4.m_implicit_cursor);
+ if (Lex->sp_block_finalize(thd, tmp)) // The outer DECLARE..BEGIN..END
+ MYSQL_YYABORT;
+ }
+ | sp_label REPEAT_SYM
{
if (Lex->sp_push_loop_label(thd, &$1))
MYSQL_YYABORT;
@@ -4400,6 +4494,32 @@ sp_unlabeled_control:
{
Lex->sp_pop_loop_empty_label(thd);
}
+ | FOR_SYM
+ {
+ // See "The FOR LOOP statement" comments in sql_lex.cc
+ if (Lex->maybe_start_compound_statement(thd))
+ MYSQL_YYABORT;
+ Lex->sp_block_init(thd); // The outer DECLARE..BEGIN..END block
+ }
+ sp_for_loop_index_and_bounds
+ {
+ if (Lex->sp_push_loop_empty_label(thd)) // The inner WHILE block
+ MYSQL_YYABORT;
+ if (Lex->sp_for_loop_condition_test(thd, $3))
+ MYSQL_YYABORT;
+ }
+ DO_SYM
+ sp_proc_stmts1
+ END FOR_SYM
+ {
+ Lex_spblock tmp;
+ tmp.curs= MY_TEST($3.m_implicit_cursor);
+ if (Lex->sp_for_loop_finalize(thd, $3))
+ MYSQL_YYABORT;
+ Lex->sp_pop_loop_empty_label(thd); // The inner WHILE block
+ if (Lex->sp_block_finalize(thd, tmp)) // The outer DECLARE..BEGIN..END
+ MYSQL_YYABORT;
+ }
| REPEAT_SYM
{
if (Lex->sp_push_loop_empty_label(thd))
@@ -7346,7 +7466,7 @@ alter:
Lex->create_info.set($2);
Lex->sql_command= SQLCOM_ALTER_USER;
}
- | ALTER SEQUENCE_SYM opt_if_exists_table_element
+ | ALTER SEQUENCE_SYM opt_if_exists
{
LEX *lex= Lex;
lex->name= null_clex_str;
@@ -7369,7 +7489,7 @@ alter:
sequence_defs
{
/* Create a generic ALTER SEQUENCE statment. */
- Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence();
+ Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence($3);
if (Lex->m_sql_cmd == NULL)
MYSQL_YYABORT;
}
@@ -13628,7 +13748,7 @@ flush_option:
{ Lex->type|= REFRESH_GENERAL_LOG; }
| SLOW LOGS_SYM
{ Lex->type|= REFRESH_SLOW_LOG; }
- | BINARY LOGS_SYM
+ | BINARY LOGS_SYM opt_delete_gtid_domain
{ Lex->type|= REFRESH_BINARY_LOG; }
| RELAY LOGS_SYM optional_connection_name
{
@@ -13685,6 +13805,24 @@ opt_table_list:
| table_list {}
;
+opt_delete_gtid_domain:
+ /* empty */ {}
+ | DELETE_DOMAIN_ID_SYM '=' '(' delete_domain_id_list ')'
+ {}
+ ;
+delete_domain_id_list:
+ /* Empty */
+ | delete_domain_id
+ | delete_domain_id_list ',' delete_domain_id
+ ;
+
+delete_domain_id:
+ ulong_num
+ {
+ insert_dynamic(&Lex->delete_gtid_domain, (uchar*) &($1));
+ }
+ ;
+
optional_flush_tables_arguments:
/* empty */ {$$= 0;}
| AND_SYM DISABLE_SYM CHECKPOINT_SYM {$$= REFRESH_CHECKPOINT; }
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index 0c5c0f85f9b..fb14acac902 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -436,6 +436,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token DEFINER_SYM
%token DELAYED_SYM
%token DELAY_KEY_WRITE_SYM
+%token DELETE_DOMAIN_ID_SYM
%token DELETE_SYM /* SQL-2003-R */
%token DENSE_RANK_SYM
%token DESC /* SQL-2003-N */
@@ -1030,13 +1031,17 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident_or_text
IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
opt_component key_cache_name
- sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
+ sp_opt_label BIN_NUM TEXT_STRING_filesystem ident_or_empty
opt_constraint constraint opt_ident
- label_declaration_oracle labels_declaration_oracle
ident_directly_assignable
sp_decl_ident
sp_block_label opt_place opt_db
+%type <lex_str>
+ label_ident
+ label_declaration_oracle
+ labels_declaration_oracle
+
%type <lex_string_with_metadata>
TEXT_STRING
NCHAR_STRING
@@ -4090,25 +4095,8 @@ sp_for_loop_bounds:
}
| IN_SYM opt_sp_for_loop_direction '(' sp_cursor_stmt ')'
{
- Item *item;
- DBUG_ASSERT(Lex->sphead);
- LEX_CSTRING name= {STRING_WITH_LEN("[implicit_cursor]") };
- if (Lex->sp_declare_cursor(thd, &name, $4, NULL, true))
- MYSQL_YYABORT;
- if (!($$.m_index= new (thd->mem_root) sp_assignment_lex(thd, thd->lex)))
+ if (Lex->sp_for_loop_implicit_cursor_statement(thd, &$$, $4))
MYSQL_YYABORT;
- $$.m_index->sp_lex_in_use= true;
- Lex->sphead->reset_lex(thd, $$.m_index);
- if (!(item= new (thd->mem_root) Item_field(thd,
- Lex->current_context(),
- NullS, NullS, &name)))
- MYSQL_YYABORT;
- $$.m_index->set_item_and_free_list(item, NULL);
- if (Lex->sphead->restore_lex(thd))
- MYSQL_YYABORT;
- $$.m_direction= 1;
- $$.m_upper_bound= NULL;
- $$.m_implicit_cursor= true;
}
;
@@ -7318,7 +7306,7 @@ alter:
Lex->create_info.set($2);
Lex->sql_command= SQLCOM_ALTER_USER;
}
- | ALTER SEQUENCE_SYM opt_if_exists_table_element
+ | ALTER SEQUENCE_SYM opt_if_exists
{
LEX *lex= Lex;
lex->name= null_clex_str;
@@ -7341,7 +7329,7 @@ alter:
sequence_defs
{
/* Create a generic ALTER SEQUENCE statment. */
- Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence();
+ Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence($3);
if (Lex->m_sql_cmd == NULL)
MYSQL_YYABORT;
}
diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc
index 3fdaff0504f..4ff6d5f2cfb 100644
--- a/sql/threadpool_generic.cc
+++ b/sql/threadpool_generic.cc
@@ -28,11 +28,19 @@
#endif
#ifdef HAVE_IOCP
-#define OPTIONAL_IO_POLL_READ_PARAM &overlapped
+#define OPTIONAL_IO_POLL_READ_PARAM this
#else
#define OPTIONAL_IO_POLL_READ_PARAM 0
#endif
+#ifdef _WIN32
+typedef HANDLE TP_file_handle;
+#else
+typedef int TP_file_handle;
+#define INVALID_HANDLE_VALUE -1
+#endif
+
+
#include <sql_connect.h>
#include <mysqld.h>
#include <debug_sync.h>
@@ -59,10 +67,10 @@ typedef OVERLAPPED_ENTRY native_event;
#pragma warning (disable : 4312)
#endif
-static void io_poll_close(int fd)
+static void io_poll_close(TP_file_handle fd)
{
#ifdef _WIN32
- CloseHandle((HANDLE)fd);
+ CloseHandle(fd);
#else
close(fd);
#endif
@@ -151,14 +159,17 @@ struct TP_connection_generic:public TP_connection
TP_connection_generic **prev_in_queue;
ulonglong abs_wait_timeout;
ulonglong dequeue_time;
+ TP_file_handle fd;
bool bound_to_poll_descriptor;
int waiting;
#ifdef HAVE_IOCP
OVERLAPPED overlapped;
#endif
+#ifdef _WIN32
+ enum_vio_type vio_type;
+#endif
};
-typedef TP_connection_generic TP_connection_generic;
typedef I_P_List<TP_connection_generic,
I_P_List_adapter<TP_connection_generic,
@@ -177,7 +188,7 @@ struct thread_group_t
worker_list_t waiting_threads;
worker_thread_t *listener;
pthread_attr_t *pthread_attr;
- int pollfd;
+ TP_file_handle pollfd;
int thread_count;
int active_thread_count;
int connection_count;
@@ -245,11 +256,11 @@ static void print_pool_blocked_message(bool);
Creates an io_poll descriptor
On Linux: epoll_create()
- - io_poll_associate_fd(int poll_fd, int fd, void *data, void *opt)
+ - io_poll_associate_fd(int poll_fd, TP_file_handle fd, void *data, void *opt)
Associate file descriptor with io poll descriptor
On Linux : epoll_ctl(..EPOLL_CTL_ADD))
- - io_poll_disassociate_fd(int pollfd, int fd)
+ - io_poll_disassociate_fd(TP_file_handle pollfd, TP_file_handle fd)
Associate file descriptor with io poll descriptor
On Linux: epoll_ctl(..EPOLL_CTL_DEL)
@@ -259,7 +270,7 @@ static void print_pool_blocked_message(bool);
io_poll_associate_fd() was called.
On Linux : epoll_ctl(..EPOLL_CTL_MOD)
- - io_poll_wait (int pollfd, native_event *native_events, int maxevents,
+ - io_poll_wait (TP_file_handle pollfd, native_event *native_events, int maxevents,
int timeout_ms)
wait until one or more descriptors added with io_poll_associate_fd()
@@ -276,13 +287,13 @@ static void print_pool_blocked_message(bool);
/* Early 2.6 kernel did not have EPOLLRDHUP */
#define EPOLLRDHUP 0
#endif
-static int io_poll_create()
+static TP_file_handle io_poll_create()
{
return epoll_create(1);
}
-int io_poll_associate_fd(int pollfd, int fd, void *data, void*)
+int io_poll_associate_fd(TP_file_handle pollfd, TP_file_handle fd, void *data, void*)
{
struct epoll_event ev;
ev.data.u64= 0; /* Keep valgrind happy */
@@ -293,7 +304,7 @@ int io_poll_associate_fd(int pollfd, int fd, void *data, void*)
-int io_poll_start_read(int pollfd, int fd, void *data, void *)
+int io_poll_start_read(TP_file_handle pollfd, TP_file_handle fd, void *data, void *)
{
struct epoll_event ev;
ev.data.u64= 0; /* Keep valgrind happy */
@@ -302,7 +313,7 @@ int io_poll_start_read(int pollfd, int fd, void *data, void *)
return epoll_ctl(pollfd, EPOLL_CTL_MOD, fd, &ev);
}
-int io_poll_disassociate_fd(int pollfd, int fd)
+int io_poll_disassociate_fd(TP_file_handle pollfd, TP_file_handle fd)
{
struct epoll_event ev;
return epoll_ctl(pollfd, EPOLL_CTL_DEL, fd, &ev);
@@ -314,7 +325,7 @@ int io_poll_disassociate_fd(int pollfd, int fd)
NOTE - in case of EINTR, it restarts with original timeout. Since we use
either infinite or 0 timeouts, this is not critical
*/
-int io_poll_wait(int pollfd, native_event *native_events, int maxevents,
+int io_poll_wait(TP_file_handle pollfd, native_event *native_events, int maxevents,
int timeout_ms)
{
int ret;
@@ -347,12 +358,12 @@ static void *native_event_get_userdata(native_event *event)
#endif
-int io_poll_create()
+TP_file_handle io_poll_create()
{
return kqueue();
}
-int io_poll_start_read(int pollfd, int fd, void *data,void *)
+int io_poll_start_read(TP_file_handle pollfd, TP_file_handle fd, void *data,void *)
{
struct kevent ke;
MY_EV_SET(&ke, fd, EVFILT_READ, EV_ADD|EV_ONESHOT,
@@ -361,7 +372,7 @@ int io_poll_start_read(int pollfd, int fd, void *data,void *)
}
-int io_poll_associate_fd(int pollfd, int fd, void *data,void *)
+int io_poll_associate_fd(TP_file_handle pollfd, TP_file_handle fd, void *data,void *)
{
struct kevent ke;
MY_EV_SET(&ke, fd, EVFILT_READ, EV_ADD|EV_ONESHOT,
@@ -370,7 +381,7 @@ int io_poll_associate_fd(int pollfd, int fd, void *data,void *)
}
-int io_poll_disassociate_fd(int pollfd, int fd)
+int io_poll_disassociate_fd(TP_file_handle pollfd, TP_file_handle fd)
{
struct kevent ke;
MY_EV_SET(&ke,fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
@@ -378,7 +389,7 @@ int io_poll_disassociate_fd(int pollfd, int fd)
}
-int io_poll_wait(int pollfd, struct kevent *events, int maxevents, int timeout_ms)
+int io_poll_wait(TP_file_handle pollfd, struct kevent *events, int maxevents, int timeout_ms)
{
struct timespec ts;
int ret;
@@ -403,27 +414,27 @@ static void* native_event_get_userdata(native_event *event)
#elif defined (__sun)
-static int io_poll_create()
+static TP_file_handle io_poll_create()
{
return port_create();
}
-int io_poll_start_read(int pollfd, int fd, void *data, void *)
+int io_poll_start_read(TP_file_handle pollfd, TP_file_handle fd, void *data, void *)
{
return port_associate(pollfd, PORT_SOURCE_FD, fd, POLLIN, data);
}
-static int io_poll_associate_fd(int pollfd, int fd, void *data, void *)
+static int io_poll_associate_fd(TP_file_handle pollfd, TP_file_handle fd, void *data, void *)
{
return io_poll_start_read(pollfd, fd, data, 0);
}
-int io_poll_disassociate_fd(int pollfd, int fd)
+int io_poll_disassociate_fd(TP_file_handle pollfd, TP_file_handle fd)
{
return port_dissociate(pollfd, PORT_SOURCE_FD, fd);
}
-int io_poll_wait(int pollfd, native_event *events, int maxevents, int timeout_ms)
+int io_poll_wait(TP_file_handle pollfd, native_event *events, int maxevents, int timeout_ms)
{
struct timespec ts;
int ret;
@@ -451,25 +462,32 @@ static void* native_event_get_userdata(native_event *event)
#elif defined(HAVE_IOCP)
-static int io_poll_create()
+static TP_file_handle io_poll_create()
{
- HANDLE h= CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
- return PtrToInt(h);
+ return CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
}
-int io_poll_start_read(int pollfd, int fd, void *, void *opt)
+int io_poll_start_read(TP_file_handle pollfd, TP_file_handle fd, void *, void *opt)
{
- DWORD num_bytes = 0;
static char c;
+ TP_connection_generic *con= (TP_connection_generic *)opt;
+ OVERLAPPED *overlapped= &con->overlapped;
+ if (con->vio_type == VIO_TYPE_NAMEDPIPE)
+ {
+ if (ReadFile(fd, &c, 0, NULL, overlapped))
+ return 0;
+ }
+ else
+ {
+ WSABUF buf;
+ buf.buf= &c;
+ buf.len= 0;
+ DWORD flags=0;
- WSABUF buf;
- buf.buf= &c;
- buf.len= 0;
- DWORD flags=0;
-
- if (WSARecv((SOCKET)fd, &buf, 1, &num_bytes, &flags, (OVERLAPPED *)opt, NULL) == 0)
- return 0;
+ if (WSARecv((SOCKET)fd, &buf, 1,NULL, &flags,overlapped, NULL) == 0)
+ return 0;
+ }
if (GetLastError() == ERROR_IO_PENDING)
return 0;
@@ -478,26 +496,26 @@ int io_poll_start_read(int pollfd, int fd, void *, void *opt)
}
-static int io_poll_associate_fd(int pollfd, int fd, void *data, void *opt)
+static int io_poll_associate_fd(TP_file_handle pollfd, TP_file_handle fd, void *data, void *opt)
{
- HANDLE h= CreateIoCompletionPort(IntToPtr(fd), IntToPtr(pollfd), (ULONG_PTR)data, 0);
+ HANDLE h= CreateIoCompletionPort(fd, pollfd, (ULONG_PTR)data, 0);
if (!h)
return -1;
return io_poll_start_read(pollfd,fd, 0, opt);
}
-int io_poll_disassociate_fd(int pollfd, int fd)
+int io_poll_disassociate_fd(TP_file_handle pollfd, TP_file_handle fd)
{
/* Not possible to unbind/rebind file descriptor in IOCP. */
return 0;
}
-int io_poll_wait(int pollfd, native_event *events, int maxevents, int timeout_ms)
+int io_poll_wait(TP_file_handle pollfd, native_event *events, int maxevents, int timeout_ms)
{
ULONG n;
- BOOL ok = GetQueuedCompletionStatusEx((HANDLE)pollfd, events,
+ BOOL ok = GetQueuedCompletionStatusEx(pollfd, events,
maxevents, &n, timeout_ms, FALSE);
return ok ? (int)n : -1;
@@ -1038,7 +1056,7 @@ int thread_group_init(thread_group_t *thread_group, pthread_attr_t* thread_attr)
DBUG_ENTER("thread_group_init");
thread_group->pthread_attr = thread_attr;
mysql_mutex_init(key_group_mutex, &thread_group->mutex, NULL);
- thread_group->pollfd= -1;
+ thread_group->pollfd= INVALID_HANDLE_VALUE;
thread_group->shutdown_pipe[0]= -1;
thread_group->shutdown_pipe[1]= -1;
queue_init(thread_group);
@@ -1049,10 +1067,10 @@ int thread_group_init(thread_group_t *thread_group, pthread_attr_t* thread_attr)
void thread_group_destroy(thread_group_t *thread_group)
{
mysql_mutex_destroy(&thread_group->mutex);
- if (thread_group->pollfd != -1)
+ if (thread_group->pollfd != INVALID_HANDLE_VALUE)
{
io_poll_close(thread_group->pollfd);
- thread_group->pollfd= -1;
+ thread_group->pollfd= INVALID_HANDLE_VALUE;
}
#ifndef HAVE_IOCP
for(int i=0; i < 2; i++)
@@ -1109,7 +1127,7 @@ static int wake_listener(thread_group_t *thread_group)
if (write(thread_group->shutdown_pipe[1], &c, 1) < 0)
return -1;
#else
- PostQueuedCompletionStatus((HANDLE)thread_group->pollfd, 0, 0, 0);
+ PostQueuedCompletionStatus(thread_group->pollfd, 0, 0, 0);
#endif
return 0;
}
@@ -1432,6 +1450,16 @@ TP_connection_generic::TP_connection_generic(CONNECT *c):
, overlapped()
#endif
{
+ DBUG_ASSERT(c->vio);
+
+#ifdef _WIN32
+ vio_type= c->vio->type;
+ fd= (vio_type == VIO_TYPE_NAMEDPIPE) ?
+ c->vio->hPipe: (TP_file_handle)mysql_socket_getfd(c->vio->mysql_socket);
+#else
+ fd= mysql_socket_getfd(c->vio->mysql_socket);
+#endif
+
/* Assign connection to a group. */
thread_group_t *group=
&all_groups[c->thread_id%group_count];
@@ -1486,7 +1514,6 @@ static int change_group(TP_connection_generic *c,
thread_group_t *new_group)
{
int ret= 0;
- int fd= (int)mysql_socket_getfd(c->thd->net.vio->mysql_socket);
DBUG_ASSERT(c->thread_group == old_group);
@@ -1494,7 +1521,7 @@ static int change_group(TP_connection_generic *c,
mysql_mutex_lock(&old_group->mutex);
if (c->bound_to_poll_descriptor)
{
- io_poll_disassociate_fd(old_group->pollfd,fd);
+ io_poll_disassociate_fd(old_group->pollfd,c->fd);
c->bound_to_poll_descriptor= false;
}
c->thread_group->connection_count--;
@@ -1513,9 +1540,7 @@ static int change_group(TP_connection_generic *c,
int TP_connection_generic::start_io()
-{
- int fd= (int)mysql_socket_getfd(thd->net.vio->mysql_socket);
-
+{
#ifndef HAVE_IOCP
/*
Usually, connection will stay in the same group for the entire
@@ -1666,10 +1691,10 @@ int TP_pool_generic::set_pool_size(uint size)
{
thread_group_t *group= &all_groups[i];
mysql_mutex_lock(&group->mutex);
- if (group->pollfd == -1)
+ if (group->pollfd == INVALID_HANDLE_VALUE)
{
group->pollfd= io_poll_create();
- success= (group->pollfd >= 0);
+ success= (group->pollfd != INVALID_HANDLE_VALUE);
if(!success)
{
sql_print_error("io_poll_create() failed, errno=%d\n", errno);
@@ -1707,7 +1732,7 @@ int TP_pool_generic::set_stall_limit(uint limit)
int TP_pool_generic::get_idle_thread_count()
{
int sum=0;
- for (uint i= 0; i < threadpool_max_size && all_groups[i].pollfd >= 0; i++)
+ for (uint i= 0; i < threadpool_max_size && all_groups[i].pollfd != INVALID_HANDLE_VALUE; i++)
{
sum+= (all_groups[i].thread_count - all_groups[i].active_thread_count);
}
diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc
index 50ecacd9960..35a0020ef44 100644
--- a/sql/wsrep_hton.cc
+++ b/sql/wsrep_hton.cc
@@ -509,6 +509,9 @@ wsrep_run_wsrep_commit(THD *thd, bool all)
}
mysql_mutex_lock(&thd->LOCK_wsrep_thd);
+
+ DEBUG_SYNC(thd, "wsrep_after_replication");
+
switch(rcode) {
case 0:
/*
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index fd759717aaf..53a8f84fcff 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -2022,7 +2022,7 @@ static bool abort_replicated(THD *thd)
bool ret_code= false;
if (thd->wsrep_query_state== QUERY_COMMITTING)
{
- WSREP_DEBUG("aborting replicated trx: %lu", (ulong) thd->real_id);
+ WSREP_DEBUG("aborting replicated trx: %llu", (ulonglong)(thd->real_id));
(void)wsrep_abort_thd(thd, thd, TRUE);
ret_code= true;
diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc
index 8107ab12c6b..188fa3e292b 100644
--- a/sql/wsrep_var.cc
+++ b/sql/wsrep_var.cc
@@ -327,8 +327,9 @@ bool wsrep_provider_update (sys_var *self, THD* thd, enum_var_type type)
if (wsrep_inited == 1)
wsrep_deinit(false);
- char* tmp= strdup(wsrep_provider); // wsrep_init() rewrites provider
+ char* tmp= strdup(wsrep_provider); // wsrep_init() rewrites provider
//when fails
+
if (wsrep_init())
{
my_error(ER_CANT_OPEN_LIBRARY, MYF(0), tmp, my_error, "wsrep_init failed");